aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog9
-rw-r--r--gcc/c-family/ChangeLog3
-rw-r--r--gcc/c-family/c-omp.c113
-rw-r--r--gcc/omp-general.c366
-rw-r--r--gcc/omp-general.h1
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-11.c83
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-6.c12
-rw-r--r--gcc/testsuite/c-c++-common/gomp/declare-variant-7.c10
9 files changed, 475 insertions, 127 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 796f5e9..17beb66 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,12 @@
+2019-11-02 Jakub Jelinek <jakub@redhat.com>
+
+ * 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.
+
2019-11-01 Martin Sebor <msebor@redhat.com>
PR middle-end/91679
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 9bc2190..dfc78a4 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,5 +1,8 @@
2019-11-02 Jakub Jelinek <jakub@redhat.com>
+ * c-omp.c (c_omp_mark_declare_variant): Use
+ omp_context_selector_set_compare.
+
PR c++/88335 - Implement P1073R3: Immediate functions
* c-common.h (enum rid): Add RID_CONSTEVAL.
* c-common.c (c_common_reswords): Add consteval.
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index 4f5a6ed..fdf778f 100644
--- a/gcc/c-family/c-omp.c
+++ b/gcc/c-family/c-omp.c
@@ -2275,113 +2275,10 @@ c_omp_mark_declare_variant (location_t loc, tree variant, tree construct)
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<tree,16> data_sharing;
- auto_vec<tree,16> 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<tree> *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 %<constructor%> "
+ 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 %<construct%> "
"selector sets", variant);
}
diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index 82f4746..6700e7f 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -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<tree,16> data_sharing;
+ auto_vec<tree,16> 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<tree> *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 <tree, 16> 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;
}
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index c0c294d..c6f95eb 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -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);
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5473b25..e8a3856 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,10 @@
2019-11-02 Jakub Jelinek <jakub@redhat.com>
+ * 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.
+
PR c++/88335 - Implement P1073R3: Immediate functions
* g++.dg/cpp2a/consteval1.C: New test.
* g++.dg/cpp2a/consteval2.C: New test.
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-11.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-11.c
new file mode 100644
index 0000000..9879a9b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-11.c
@@ -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-*-* } } } } } */
+}
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c
index 9ccfd0f..159da07 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-6.c
@@ -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);
diff --git a/gcc/testsuite/c-c++-common/gomp/declare-variant-7.c b/gcc/testsuite/c-c++-common/gomp/declare-variant-7.c
index 1df6338..4eebcbc 100644
--- a/gcc/testsuite/c-c++-common/gomp/declare-variant-7.c
+++ b/gcc/testsuite/c-c++-common/gomp/declare-variant-7.c
@@ -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);