From patchwork Fri Nov 1 23:32:24 2019 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Jakub Jelinek X-Patchwork-Id: 1188257 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-512254-incoming=patchwork.ozlabs.org@gcc.gnu.org; receiver=) Authentication-Results: ozlabs.org; dmarc=fail (p=none dis=none) header.from=redhat.com Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b="RGDSIa+J"; dkim=fail reason="signature verification failed" (1024-bit key; unprotected) header.d=redhat.com header.i=@redhat.com header.b="hSZ0Q5iD"; 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 474dlh22K4z9sNx for ; Sat, 2 Nov 2019 10:32: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:date :from:to:subject:message-id:reply-to:mime-version:content-type :content-transfer-encoding; q=dns; s=default; b=y3YkJfglZYSPG0Kz 9cmHOb52Locw08FRdvnPUNBxC0dgc0yOdGLUj494TlHSubDRU9wq/nTSKWITUyV/ gLjsRRaTeKLtbag3NuUHuh6DjoDfIZcUsTzBPo7/hKzVVqORM6ZwedUVW6cA9oGX 1WGKsA0KhuH4YIdktDjSfN60EVA= 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:date :from:to:subject:message-id:reply-to:mime-version:content-type :content-transfer-encoding; s=default; bh=Q9F4DDUaKw+IgKBuefF4/y JGRjQ=; b=RGDSIa+JGo0tBxDgM4va6QGC/T3kA7m8qqxsD3usl8vJctkbMxLlC6 5RlIL2FaKEoC3awI3Sk4vAHibBk0xur04WZoNYs1G+m3e5w3JJRtnuMeakqemmuo +0FFzZom+v/9ZYpSuRMJ6bT0wvL6UmW9QZ5C3KuWwkIA2A7nQ2t+4= Received: (qmail 17283 invoked by alias); 1 Nov 2019 23:32:36 -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 17270 invoked by uid 89); 1 Nov 2019 23:32:35 -0000 Authentication-Results: sourceware.org; auth=none X-Spam-SWARE-Status: No, score=-7.6 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_2, GIT_PATCH_3 autolearn=ham version=3.3.1 spammy=51, sk:avx512b, OMP_CLAUSE_DECL, omp_clause_decl X-HELO: us-smtp-delivery-1.mimecast.com Received: from us-smtp-2.mimecast.com (HELO us-smtp-delivery-1.mimecast.com) (205.139.110.61) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Fri, 01 Nov 2019 23:32:32 +0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1572651149; h=from:from:reply-to:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:mime-version:mime-version: content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=eb/H5UnPXnjzMnFRxKn3Ce4iJxtIdUF1yuf84quSwlw=; b=hSZ0Q5iDyGq81pHUey4gnfMeDbfFPtkolJL3BIboACjAg0SicWZlBZfPPyQRTMpsMivzBd n9IdXw7aZta5OUB4RhEO4kjziaK2UWCGSkHRNJI5/OjkIvJm32MLqCepbtXmmn+0ozfb+z 1D8YvJaPlLQBHswsL2b3v0MU2ENLpps= Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) (Using TLS) by relay.mimecast.com with ESMTP id us-mta-434-TtKlKDlxMsKrMTqbzDy24A-1; Fri, 01 Nov 2019 19:32:28 -0400 Received: from smtp.corp.redhat.com (int-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.12]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 41217800D49 for ; Fri, 1 Nov 2019 23:32:27 +0000 (UTC) Received: from tucnak.zalov.cz (unknown [10.36.118.135]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 934A760BE2 for ; Fri, 1 Nov 2019 23:32:26 +0000 (UTC) Received: from tucnak.zalov.cz (localhost [127.0.0.1]) by tucnak.zalov.cz (8.15.2/8.15.2) with ESMTP id xA1NWOcW013851 for ; Sat, 2 Nov 2019 00:32:24 +0100 Received: (from jakub@localhost) by tucnak.zalov.cz (8.15.2/8.15.2/Submit) id xA1NWOgX013850 for gcc-patches@gcc.gnu.org; Sat, 2 Nov 2019 00:32:24 +0100 Date: Sat, 2 Nov 2019 00:32:24 +0100 From: Jakub Jelinek To: gcc-patches@gcc.gnu.org Subject: [committed] OpenMP declare variant context strict subset testing Message-ID: <20191101233224.GW4650@tucnak> Reply-To: Jakub Jelinek MIME-Version: 1.0 User-Agent: Mutt/1.11.3 (2019-02-01) X-Mimecast-Spam-Score: 0 Content-Disposition: inline X-IsSubscribed: yes Hi! The following patch implements one sentence from the OpenMP 5 standard: "A context selector that is a strict subset of another context selector has a score of zero." I have scoring mostly written too, but haven't added testcases yet, so that will be in a follow-up patch. Bootstrapped/regtested on x86_64-linux and i686-linux, committed to trunk. 2019-11-02 Jakub Jelinek * omp-general.h (omp_context_selector_set_compare): Declare. * omp-general.c (omp_construct_simd_compare, omp_context_selector_props_compare, omp_context_selector_set_compare, omp_context_selector_compare): New functions. (omp_resolve_declare_variant): Prune variants that are strict subset of another variant. c-family/ * c-omp.c (c_omp_mark_declare_variant): Use omp_context_selector_set_compare. testsuite/ * c-c++-common/gomp/declare-variant-6.c: Expect construct rather than constructor in diagnostic messages. * c-c++-common/gomp/declare-variant-7.c: Likewise. * c-c++-common/gomp/declare-variant-11.c: New test. Jakub --- gcc/omp-general.h.jj 2019-10-25 00:27:43.618318678 +0200 +++ gcc/omp-general.h 2019-11-01 12:37:33.806852041 +0100 @@ -86,6 +86,7 @@ extern poly_uint64 omp_max_vf (void); extern int omp_max_simt_vf (void); extern int omp_constructor_traits_to_codes (tree, enum tree_code *); extern int omp_context_selector_matches (tree); +extern int omp_context_selector_set_compare (const char *, tree, tree); extern tree omp_resolve_declare_variant (tree); extern tree oacc_launch_pack (unsigned code, tree device, unsigned op); extern tree oacc_replace_fn_attrib_attr (tree attribs, tree dims); --- gcc/omp-general.c.jj 2019-10-31 11:05:50.519136130 +0100 +++ gcc/omp-general.c 2019-11-01 14:53:18.593998097 +0100 @@ -947,6 +947,320 @@ omp_context_selector_matches (tree ctx) return ret; } +/* Compare construct={simd} CLAUSES1 with CLAUSES2, return 0/-1/1/2 as + in omp_context_selector_set_compare. */ + +static int +omp_construct_simd_compare (tree clauses1, tree clauses2) +{ + if (clauses1 == NULL_TREE) + return clauses2 == NULL_TREE ? 0 : -1; + if (clauses2 == NULL_TREE) + return 1; + + int r = 0; + struct declare_variant_simd_data { + bool inbranch, notinbranch; + tree simdlen; + auto_vec data_sharing; + auto_vec aligned; + declare_variant_simd_data () + : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {} + } data[2]; + unsigned int i; + for (i = 0; i < 2; i++) + for (tree c = i ? clauses2 : clauses1; c; c = OMP_CLAUSE_CHAIN (c)) + { + vec *v; + switch (OMP_CLAUSE_CODE (c)) + { + case OMP_CLAUSE_INBRANCH: + data[i].inbranch = true; + continue; + case OMP_CLAUSE_NOTINBRANCH: + data[i].notinbranch = true; + continue; + case OMP_CLAUSE_SIMDLEN: + data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c); + continue; + case OMP_CLAUSE_UNIFORM: + case OMP_CLAUSE_LINEAR: + v = &data[i].data_sharing; + break; + case OMP_CLAUSE_ALIGNED: + v = &data[i].aligned; + break; + default: + gcc_unreachable (); + } + unsigned HOST_WIDE_INT argno = tree_to_uhwi (OMP_CLAUSE_DECL (c)); + if (argno >= v->length ()) + v->safe_grow_cleared (argno + 1); + (*v)[argno] = c; + } + /* Here, r is used as a bitmask, 2 is set if CLAUSES1 has something + CLAUSES2 doesn't, 1 is set if CLAUSES2 has something CLAUSES1 + doesn't. Thus, r == 3 implies return value 2, r == 1 implies + -1, r == 2 implies 1 and r == 0 implies 0. */ + if (data[0].inbranch != data[1].inbranch) + r |= data[0].inbranch ? 2 : 1; + if (data[0].notinbranch != data[1].notinbranch) + r |= data[0].notinbranch ? 2 : 1; + if (!simple_cst_equal (data[0].simdlen, data[1].simdlen)) + { + if (data[0].simdlen && data[1].simdlen) + return 2; + r |= data[0].simdlen ? 2 : 1; + } + if (data[0].data_sharing.length () < data[1].data_sharing.length () + || data[0].aligned.length () < data[1].aligned.length ()) + r |= 1; + tree c1, c2; + FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1) + { + c2 = (i < data[1].data_sharing.length () + ? data[1].data_sharing[i] : NULL_TREE); + if ((c1 == NULL_TREE) != (c2 == NULL_TREE)) + { + r |= c1 != NULL_TREE ? 2 : 1; + continue; + } + if (c1 == NULL_TREE) + continue; + if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2)) + return 2; + if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR) + continue; + if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1) + != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2)) + return 2; + if (OMP_CLAUSE_LINEAR_KIND (c1) != OMP_CLAUSE_LINEAR_KIND (c2)) + return 2; + if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1), + OMP_CLAUSE_LINEAR_STEP (c2))) + return 2; + } + FOR_EACH_VEC_ELT (data[0].aligned, i, c1) + { + c2 = i < data[1].aligned.length () ? data[1].aligned[i] : NULL_TREE; + if ((c1 == NULL_TREE) != (c2 == NULL_TREE)) + { + r |= c1 != NULL_TREE ? 2 : 1; + continue; + } + if (c1 == NULL_TREE) + continue; + if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1), + OMP_CLAUSE_ALIGNED_ALIGNMENT (c2))) + return 2; + } + switch (r) + { + case 0: return 0; + case 1: return -1; + case 2: return 1; + case 3: return 2; + default: gcc_unreachable (); + } +} + +/* Compare properties of selectors SEL from SET other than construct. + Return 0/-1/1/2 as in omp_context_selector_set_compare. + Unlike set names or selector names, properties can have duplicates. */ + +static int +omp_context_selector_props_compare (const char *set, const char *sel, + tree ctx1, tree ctx2) +{ + int ret = 0; + for (int pass = 0; pass < 2; pass++) + for (tree t1 = pass ? ctx2 : ctx1; t1; t1 = TREE_CHAIN (t1)) + { + tree t2; + for (t2 = pass ? ctx1 : ctx2; t2; t2 = TREE_CHAIN (t2)) + if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2)) + { + if (TREE_PURPOSE (t1) == NULL_TREE) + { + if (set[0] == 'u' && strcmp (sel, "condition") == 0) + { + if (integer_zerop (TREE_VALUE (t1)) + != integer_zerop (TREE_VALUE (t2))) + return 2; + break; + } + if (simple_cst_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + break; + } + else if (strcmp (IDENTIFIER_POINTER (TREE_PURPOSE (t1)), + " score") == 0) + { + if (!simple_cst_equal (TREE_VALUE (t1), TREE_VALUE (t2))) + return 2; + break; + } + else + break; + } + if (t2 == NULL_TREE) + { + int r = pass ? -1 : 1; + if (ret && ret != r) + return 2; + else if (pass) + return r; + else + { + ret = r; + break; + } + } + } + return ret; +} + +/* Compare single context selector sets CTX1 and CTX2 with SET name. + Return 0 if CTX1 is equal to CTX2, + -1 if CTX1 is a strict subset of CTX2, + 1 if CTX2 is a strict subset of CTX1, or + 2 if neither context is a subset of another one. */ + +int +omp_context_selector_set_compare (const char *set, tree ctx1, tree ctx2) +{ + bool swapped = false; + int ret = 0; + int len1 = list_length (ctx1); + int len2 = list_length (ctx2); + int cnt = 0; + if (len1 < len2) + { + swapped = true; + std::swap (ctx1, ctx2); + std::swap (len1, len2); + } + if (set[0] == 'c') + { + tree t1; + tree t2 = ctx2; + tree simd = get_identifier ("simd"); + /* Handle construct set specially. In this case the order + of the selector matters too. */ + for (t1 = ctx1; t1; t1 = TREE_CHAIN (t1)) + if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2)) + { + int r = 0; + if (TREE_PURPOSE (t1) == simd) + r = omp_construct_simd_compare (TREE_VALUE (t1), + TREE_VALUE (t2)); + if (r == 2 || (ret && r && (ret < 0) != (r < 0))) + return 2; + if (ret == 0) + ret = r; + t2 = TREE_CHAIN (t2); + if (t2 == NULL_TREE) + { + t1 = TREE_CHAIN (t1); + break; + } + } + else if (ret < 0) + return 2; + else + ret = 1; + if (t2 != NULL_TREE) + return 2; + if (t1 != NULL_TREE) + { + if (ret < 0) + return 2; + ret = 1; + } + if (ret == 0) + return 0; + return swapped ? -ret : ret; + } + for (tree t1 = ctx1; t1; t1 = TREE_CHAIN (t1)) + { + tree t2; + for (t2 = ctx2; t2; t2 = TREE_CHAIN (t2)) + if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2)) + { + const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t1)); + int r = omp_context_selector_props_compare (set, sel, + TREE_VALUE (t1), + TREE_VALUE (t2)); + if (r == 2 || (ret && r && (ret < 0) != (r < 0))) + return 2; + if (ret == 0) + ret = r; + cnt++; + break; + } + if (t2 == NULL_TREE) + { + if (ret == -1) + return 2; + ret = 1; + } + } + if (cnt < len2) + return 2; + if (ret == 0) + return 0; + return swapped ? -ret : ret; +} + +/* Compare whole context selector specification CTX1 and CTX2. + Return 0 if CTX1 is equal to CTX2, + -1 if CTX1 is a strict subset of CTX2, + 1 if CTX2 is a strict subset of CTX1, or + 2 if neither context is a subset of another one. */ + +static int +omp_context_selector_compare (tree ctx1, tree ctx2) +{ + bool swapped = false; + int ret = 0; + int len1 = list_length (ctx1); + int len2 = list_length (ctx2); + int cnt = 0; + if (len1 < len2) + { + swapped = true; + std::swap (ctx1, ctx2); + std::swap (len1, len2); + } + for (tree t1 = ctx1; t1; t1 = TREE_CHAIN (t1)) + { + tree t2; + for (t2 = ctx2; t2; t2 = TREE_CHAIN (t2)) + if (TREE_PURPOSE (t1) == TREE_PURPOSE (t2)) + { + const char *set = IDENTIFIER_POINTER (TREE_PURPOSE (t1)); + int r = omp_context_selector_set_compare (set, TREE_VALUE (t1), + TREE_VALUE (t2)); + if (r == 2 || (ret && r && (ret < 0) != (r < 0))) + return 2; + if (ret == 0) + ret = r; + cnt++; + break; + } + if (t2 == NULL_TREE) + { + if (ret == -1) + return 2; + ret = 1; + } + } + if (cnt < len2) + return 2; + if (ret == 0) + return 0; + return swapped ? -ret : ret; +} + /* Try to resolve declare variant, return the variant decl if it should be used instead of base, or base otherwise. */ @@ -954,11 +1268,14 @@ tree omp_resolve_declare_variant (tree base) { tree variant = NULL_TREE; + auto_vec variants; for (tree attr = DECL_ATTRIBUTES (base); attr; attr = TREE_CHAIN (attr)) { attr = lookup_attribute ("omp declare variant base", attr); if (attr == NULL_TREE) break; + if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr))) != FUNCTION_DECL) + continue; switch (omp_context_selector_matches (TREE_VALUE (TREE_VALUE (attr)))) { case 0: @@ -968,16 +1285,49 @@ omp_resolve_declare_variant (tree base) /* Needs to be deferred. */ return base; default: - /* FIXME: Scoring not implemented yet, so just resolve it - if there is a single variant only. */ - if (variant) - return base; - if (TREE_CODE (TREE_PURPOSE (TREE_VALUE (attr))) == FUNCTION_DECL) - variant = TREE_PURPOSE (TREE_VALUE (attr)); - else - return base; + variants.safe_push (attr); } } + if (variants.length () == 0) + return base; + if (variants.length () == 1) + return TREE_PURPOSE (TREE_VALUE (variants[0])); + + /* A context selector that is a strict subset of another context selector has a score + of zero. */ + tree attr1, attr2; + unsigned int i, j; + FOR_EACH_VEC_ELT (variants, i, attr1) + if (attr1) + { + tree ctx1 = TREE_VALUE (TREE_VALUE (attr1)); + FOR_EACH_VEC_ELT_FROM (variants, j, attr2, i + 1) + if (attr2) + { + tree ctx2 = TREE_VALUE (TREE_VALUE (attr2)); + int r = omp_context_selector_compare (ctx1, ctx2); + if (r == -1) + { + /* ctx1 is a strict subset of ctx2, remove + attr1 from the vector. */ + variants[i] = NULL_TREE; + break; + } + else if (r == 1) + /* ctx2 is a strict subset of ctx1, remove attr2 + from the vector. */ + variants[j] = NULL_TREE; + } + } + /* FIXME: Scoring not implemented yet, so just resolve it + if there is a single variant left. */ + FOR_EACH_VEC_ELT (variants, i, attr1) + if (attr1) + { + if (variant) + return base; + variant = TREE_PURPOSE (TREE_VALUE (attr1)); + } return variant ? variant : base; } --- gcc/c-family/c-omp.c.jj 2019-10-25 00:27:43.000000000 +0200 +++ gcc/c-family/c-omp.c 2019-11-01 13:06:51.462874386 +0100 @@ -2275,113 +2275,10 @@ c_omp_mark_declare_variant (location_t l DECL_ATTRIBUTES (variant) = attr; return; } - tree t1 = TREE_VALUE (attr); - tree t2 = construct; - tree simd = get_identifier ("simd"); - while (t1 && t2) - { - if (TREE_PURPOSE (t1) != TREE_PURPOSE (t2)) - break; - if (TREE_PURPOSE (t1) == simd) - { - if ((TREE_VALUE (t1) == NULL_TREE) - != (TREE_VALUE (t2) == NULL_TREE)) - break; - if (TREE_VALUE (t1)) - { - struct declare_variant_simd_data { - bool inbranch, notinbranch; - tree simdlen; - auto_vec data_sharing; - auto_vec aligned; - declare_variant_simd_data () - : inbranch(false), notinbranch(false), simdlen(NULL_TREE) {} - } data[2]; - unsigned int i; - for (i = 0; i < 2; i++) - for (tree c = TREE_VALUE (i ? t2 : t1); - c; c = OMP_CLAUSE_CHAIN (c)) - { - vec *v; - switch (OMP_CLAUSE_CODE (c)) - { - case OMP_CLAUSE_INBRANCH: - data[i].inbranch = true; - continue; - case OMP_CLAUSE_NOTINBRANCH: - data[i].notinbranch = true; - continue; - case OMP_CLAUSE_SIMDLEN: - data[i].simdlen = OMP_CLAUSE_SIMDLEN_EXPR (c); - continue; - case OMP_CLAUSE_UNIFORM: - case OMP_CLAUSE_LINEAR: - v = &data[i].data_sharing; - break; - case OMP_CLAUSE_ALIGNED: - v = &data[i].aligned; - break; - default: - gcc_unreachable (); - } - unsigned HOST_WIDE_INT argno - = tree_to_uhwi (OMP_CLAUSE_DECL (c)); - if (argno >= v->length ()) - v->safe_grow_cleared (argno + 1); - (*v)[argno] = c; - } - if (data[0].inbranch != data[1].inbranch - || data[0].notinbranch != data[1].notinbranch - || !simple_cst_equal (data[0].simdlen, - data[1].simdlen) - || (data[0].data_sharing.length () - != data[1].data_sharing.length ()) - || (data[0].aligned.length () - != data[1].aligned.length ())) - break; - tree c1, c2; - FOR_EACH_VEC_ELT (data[0].data_sharing, i, c1) - { - c2 = data[1].data_sharing[i]; - if ((c1 == NULL_TREE) != (c2 == NULL_TREE)) - break; - if (c1 == NULL_TREE) - continue; - if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_CODE (c2)) - break; - if (OMP_CLAUSE_CODE (c1) != OMP_CLAUSE_LINEAR) - continue; - if (OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c1) - != OMP_CLAUSE_LINEAR_VARIABLE_STRIDE (c2)) - break; - if (OMP_CLAUSE_LINEAR_KIND (c1) - != OMP_CLAUSE_LINEAR_KIND (c2)) - break; - if (!simple_cst_equal (OMP_CLAUSE_LINEAR_STEP (c1), - OMP_CLAUSE_LINEAR_STEP (c2))) - break; - } - if (i < data[0].data_sharing.length ()) - break; - FOR_EACH_VEC_ELT (data[0].aligned, i, c1) - { - c2 = data[1].aligned[i]; - if ((c1 == NULL_TREE) != (c2 == NULL_TREE)) - break; - if (c1 == NULL_TREE) - continue; - if (!simple_cst_equal (OMP_CLAUSE_ALIGNED_ALIGNMENT (c1), - OMP_CLAUSE_ALIGNED_ALIGNMENT (c2))) - break; - } - if (i < data[0].aligned.length ()) - break; - } - } - t1 = TREE_CHAIN (t1); - t2 = TREE_CHAIN (t2); - } - if (t1 || t2) - error_at (loc, "%qD used as a variant with incompatible % " + if ((TREE_VALUE (attr) != NULL_TREE) != (construct != NULL_TREE) + || (construct != NULL_TREE + && omp_context_selector_set_compare ("construct", TREE_VALUE (attr), + construct))) + error_at (loc, "%qD used as a variant with incompatible % " "selector sets", variant); } --- gcc/testsuite/c-c++-common/gomp/declare-variant-6.c.jj 2019-10-30 12:38:38.187142834 +0100 +++ gcc/testsuite/c-c++-common/gomp/declare-variant-6.c 2019-11-01 13:08:44.300144825 +0100 @@ -7,29 +7,29 @@ double f4 (int, long, float); double f5 (int, long, float); #pragma omp declare variant (f5) match (user={condition(0)}) double f6 (int, long, float); -#pragma omp declare variant (f5) match (construct={parallel},user={condition(score(1):1)}) /* { dg-error "'\[^'\n\r]*f5\[^'\n\r]*' used as a variant with incompatible 'constructor' selector sets" } */ +#pragma omp declare variant (f5) match (construct={parallel},user={condition(score(1):1)}) /* { dg-error "'\[^'\n\r]*f5\[^'\n\r]*' used as a variant with incompatible 'construct' selector sets" } */ double f7 (int, long, float); double f8 (int, long, float); #pragma omp declare variant (f8) match (user={condition(0)},construct={for}) double f9 (int, long, float); -#pragma omp declare variant (f8) match (user={condition(1)}) /* { dg-error "'\[^'\n\r]*f8\[^'\n\r]*' used as a variant with incompatible 'constructor' selector sets" } */ +#pragma omp declare variant (f8) match (user={condition(1)}) /* { dg-error "'\[^'\n\r]*f8\[^'\n\r]*' used as a variant with incompatible 'construct' selector sets" } */ double f10 (int, long, float); double f11 (int, long, float); #pragma omp declare variant (f11) match (construct={target,teams,parallel,for}) double f12 (int, long, float); #pragma omp declare variant (f11) match (user={condition(score(1):1)},construct={target,teams,parallel,for}) double f13 (int, long, float); -#pragma omp declare variant (f11) match (implementation={vendor(gnu)},construct={target,teams,parallel}) /* { dg-error "'\[^'\n\r]*f11\[^'\n\r]*' used as a variant with incompatible 'constructor' selector sets" } */ +#pragma omp declare variant (f11) match (implementation={vendor(gnu)},construct={target,teams,parallel}) /* { dg-error "'\[^'\n\r]*f11\[^'\n\r]*' used as a variant with incompatible 'construct' selector sets" } */ double f14 (int, long, float); -#pragma omp declare variant (f11) match (device={kind(any)},construct={teams,parallel}) /* { dg-error "'\[^'\n\r]*f11\[^'\n\r]*' used as a variant with incompatible 'constructor' selector sets" } */ +#pragma omp declare variant (f11) match (device={kind(any)},construct={teams,parallel}) /* { dg-error "'\[^'\n\r]*f11\[^'\n\r]*' used as a variant with incompatible 'construct' selector sets" } */ double f15 (int, long, float); double f16 (int, long, float); #pragma omp declare variant (f16) match (construct={teams,parallel}) double f17 (int, long, float); -#pragma omp declare variant (f16) match(construct={teams,parallel,for}) /* { dg-error "'\[^'\n\r]*f16\[^'\n\r]*' used as a variant with incompatible 'constructor' selector sets" } */ +#pragma omp declare variant (f16) match(construct={teams,parallel,for}) /* { dg-error "'\[^'\n\r]*f16\[^'\n\r]*' used as a variant with incompatible 'construct' selector sets" } */ double f18 (int, long, float); double f19 (int, long, float); #pragma omp declare variant (f19) match (construct={parallel}) double f20 (int, long, float); -#pragma omp declare variant (f19) match (construct={for},implementation={vendor(gnu,llvm)}) /* { dg-error "'\[^'\n\r]*f19\[^'\n\r]*' used as a variant with incompatible 'constructor' selector sets" } */ +#pragma omp declare variant (f19) match (construct={for},implementation={vendor(gnu,llvm)}) /* { dg-error "'\[^'\n\r]*f19\[^'\n\r]*' used as a variant with incompatible 'construct' selector sets" } */ double f21 (int, long, float); --- gcc/testsuite/c-c++-common/gomp/declare-variant-7.c.jj 2019-10-14 08:52:03.747578485 +0200 +++ gcc/testsuite/c-c++-common/gomp/declare-variant-7.c 2019-11-01 13:09:41.771263923 +0100 @@ -13,23 +13,23 @@ __v4si f3 (__v4si, int, __v4si); int f4 (float x, float y, float *z); #pragma omp declare variant (f1) match (construct={parallel,for,simd(uniform(w),simdlen(8*2-12),aligned(w:4*sizeof (float)),notinbranch)}) int f5 (float u, float v, float *w); -#pragma omp declare variant (f1) match (construct={parallel,for,simd(linear(w),notinbranch,simdlen(4),aligned(w:4*sizeof (float)))}) /* { dg-error "'f1' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */ +#pragma omp declare variant (f1) match (construct={parallel,for,simd(linear(w),notinbranch,simdlen(4),aligned(w:4*sizeof (float)))}) /* { dg-error "'f1' used as a variant with incompatible 'construct' selector sets" "" { target c } } */ int f6 (float u, float v, float *w); -#pragma omp declare variant (f1) match (construct={parallel,for,simd(uniform(w),notinbranch,simdlen(4),aligned(w:2*sizeof (float)))}) /* { dg-error "'f1' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */ +#pragma omp declare variant (f1) match (construct={parallel,for,simd(uniform(w),notinbranch,simdlen(4),aligned(w:2*sizeof (float)))}) /* { dg-error "'f1' used as a variant with incompatible 'construct' selector sets" "" { target c } } */ int f7 (float u, float v, float *w); -#pragma omp declare variant (f1) match (construct={parallel,for,simd(uniform(w),notinbranch,simdlen(4),aligned(w))}) /* { dg-error "'f1' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */ +#pragma omp declare variant (f1) match (construct={parallel,for,simd(uniform(w),notinbranch,simdlen(4),aligned(w))}) /* { dg-error "'f1' used as a variant with incompatible 'construct' selector sets" "" { target c } } */ int f8 (float u, float v, float *w); #pragma omp declare variant (f2) match (construct={for,simd(uniform(z),simdlen(8),notinbranch)}) int f9 (float x, float y, float *z); #pragma omp declare variant (f2) match (construct={for,simd(notinbranch,simdlen(2+2+4),uniform (q))}) int f10 (float x, float y, float *q); -#pragma omp declare variant (f2) match (construct={for,simd(linear(z:2),simdlen(8),notinbranch)}) /* { dg-error "'f2' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */ +#pragma omp declare variant (f2) match (construct={for,simd(linear(z:2),simdlen(8),notinbranch)}) /* { dg-error "'f2' used as a variant with incompatible 'construct' selector sets" "" { target c } } */ int f11 (float x, float y, float *z); #pragma omp declare variant (f3) match (construct={simd(simdlen(4),inbranch,linear(y:1))}) int f12 (int x, int y); #pragma omp declare variant (f3) match (construct={simd(inbranch, simdlen (5-1), linear (q:4-3))}) int f13 (int x, int q); -#pragma omp declare variant (f3) match (construct={simd(inbranch,simdlen(4),linear(q:2))}) /* { dg-error "'f3' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */ +#pragma omp declare variant (f3) match (construct={simd(inbranch,simdlen(4),linear(q:2))}) /* { dg-error "'f3' used as a variant with incompatible 'construct' selector sets" "" { target c } } */ int f14 (int x, int q); #pragma omp declare variant (f3) match (construct={simd(inbranch simdlen (4) linear (q:1))}) /* { dg-error "clauses in 'simd' trait should be separated by ','" } */ int f15 (int x, int q); --- gcc/testsuite/c-c++-common/gomp/declare-variant-11.c.jj 2019-11-01 13:13:46.817507882 +0100 +++ gcc/testsuite/c-c++-common/gomp/declare-variant-11.c 2019-11-01 14:31:22.285145658 +0100 @@ -0,0 +1,83 @@ +/* { dg-do compile } */ +/* { dg-additional-options "-foffload=disable -fdump-tree-gimple" } */ +/* { dg-additional-options "-mavx512bw -mavx512vl" { target { i?86-*-* x86_64-*-* } } } */ + +void f01 (void); +void f02 (void); +#pragma omp declare variant (f01) match (device={isa(avx512f,avx512vl)}) +#pragma omp declare variant (f02) match (device={isa(avx512bw,avx512vl,avx512f)}) +void f03 (void); +void f04 (void); +void f05 (void); +#pragma omp declare variant (f04) match (device={isa(avx512f,avx512vl)}) +#pragma omp declare variant (f05) match (device={isa(avx512bw,avx512vl,avx512f)}) +void f06 (void); +void f07 (void); +void f08 (void); +#pragma omp declare variant (f07) match (device={isa(sse4,sse3,avx)}) +#pragma omp declare variant (f08) match (device={isa(avx,sse3)}) +void f09 (void); +void f10 (void); +void f11 (void); +void f12 (void); +#pragma omp declare variant (f10) match (device={isa(avx512f)}) +#pragma omp declare variant (f11) match (user={condition(1)},device={isa(avx512f)},implementation={vendor(gnu)}) +#pragma omp declare variant (f12) match (user={condition(2 + 1)},device={isa(avx512f)}) +void f13 (void); +void f14 (void); +void f15 (void); +void f16 (void); +void f17 (void); +#pragma omp declare variant (f14) match (construct={teams,for}) +#pragma omp declare variant (f15) match (construct={teams,parallel,for}) +#pragma omp declare variant (f16) match (construct={for}) +#pragma omp declare variant (f17) match (construct={parallel,for}) +void f18 (void); +void f19 (void); +void f20 (void); +void f21 (void); +void f22 (void); +#pragma omp declare variant (f19) match (construct={teams,for}) +#pragma omp declare variant (f20) match (construct={teams,parallel,for}) +#pragma omp declare variant (f21) match (construct={for}) +#pragma omp declare variant (f22) match (construct={parallel,for}) +void f23 (void); +void f24 (void); +void f25 (void); +void f26 (void); +#pragma omp declare variant (f24) match (device={kind(cpu)}) +#pragma omp declare variant (f25) match (device={kind(cpu),isa(avx512f),arch(x86_64)}) +#pragma omp declare variant (f26) match (device={arch(x86_64),kind(cpu)}) +void f27 (void); + +void +test1 (void) +{ + int i; + f03 (); /* { dg-final { scan-tree-dump-times "f02 \\\(\\\);" 1 "gimple" { target i?86-*-* x86_64-*-* } } } */ + /* { dg-final { scan-tree-dump-times "f03 \\\(\\\);" 1 "gimple" { target { ! { i?86-*-* x86_64-*-* } } } } } */ + f09 (); /* { dg-final { scan-tree-dump-times "f07 \\\(\\\);" 1 "gimple" { target i?86-*-* x86_64-*-* } } } */ + /* { dg-final { scan-tree-dump-times "f09 \\\(\\\);" 1 "gimple" { target { ! { i?86-*-* x86_64-*-* } } } } } */ + f13 (); /* { dg-final { scan-tree-dump-times "f11 \\\(\\\);" 1 "gimple" { target i?86-*-* x86_64-*-* } } } */ + /* { dg-final { scan-tree-dump-times "f13 \\\(\\\);" 1 "gimple" { target { ! { i?86-*-* x86_64-*-* } } } } } */ + #pragma omp teams distribute parallel for + for (i = 0; i < 1; i++) + f18 (); /* { dg-final { scan-tree-dump-times "f15 \\\(\\\);" 1 "gimple" } } */ + #pragma omp parallel for + for (i = 0; i < 1; i++) + f23 (); /* { dg-final { scan-tree-dump-times "f22 \\\(\\\);" 1 "gimple" } } */ + f27 (); /* { dg-final { scan-tree-dump-times "f25 \\\(\\\);" 1 "gimple" { target { { i?86-*-* x86_64-*-* } && lp64 } } } } */ + /* { dg-final { scan-tree-dump-times "f24 \\\(\\\);" 1 "gimple" { target { { i?86-*-* x86_64-*-* } && { ! lp64 } } } } } */ + /* { dg-final { scan-tree-dump-times "f24 \\\(\\\);" 1 "gimple" { target { ! { nvptx*-*-* amdgcn*-*-* i?86-*-* x86_64-*-* } } } } } */ + /* { dg-final { scan-tree-dump-times "f27 \\\(\\\);" 1 "gimple" { target { nvptx*-*-* amdgcn*-*-* } } } } */ +} + +#if defined(__i386__) || defined(__x86_64__) +__attribute__((target ("no-avx512bw,avx512f,avx512vl"))) +#endif +void +test2 (void) +{ + f06 (); /* { dg-final { scan-tree-dump-times "f04 \\\(\\\);" 1 "gimple" { target i?86-*-* x86_64-*-* } } } */ + /* { dg-final { scan-tree-dump-times "f06 \\\(\\\);" 1 "gimple" { target { ! { i?86-*-* x86_64-*-* } } } } } */ +}