+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * c-common.h (c_omp_mark_declare_variant,
+ c_omp_context_selector_matches): Declare.
+ * c-omp.c: Include attribs.h, gimplify.h, cgraph.h, symbol-summary.h
+ and hsa-common.h.
+ (c_omp_get_context_selector): Support second argument NULL.
+ (c_omp_mark_declare_variant, c_omp_context_selector_matches): New
+ functions.
+ * c-attribs.c (c_common_attribute_table): Remove "omp declare variant"
+ attribute, add "omp declare variant base" and
+ "omp declare variant variant" attributes.
+
2019-10-11 Joseph Myers <joseph@codesourcery.com>
* c.opt (Wc11-c2x-compat): Add CPP(cpp_warn_c11_c2x_compat)
handle_returns_nonnull_attribute, NULL },
{ "omp declare simd", 0, -1, true, false, false, false,
handle_omp_declare_simd_attribute, NULL },
- { "omp declare variant", 0, -1, true, false, false, false,
+ { "omp declare variant base", 0, -1, true, false, false, false,
+ handle_omp_declare_variant_attribute, NULL },
+ { "omp declare variant variant", 0, -1, true, false, false, false,
handle_omp_declare_variant_attribute, NULL },
{ "simd", 0, 1, true, false, false, false,
handle_simd_attribute, NULL },
return NULL_TREE;
}
-/* Handle an "omp declare variant" attribute; arguments as in
+/* Handle an "omp declare variant {base,variant}" attribute; arguments as in
struct attribute_spec.handler. */
static tree
extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
extern tree c_omp_check_context_selector (location_t, tree);
extern tree c_omp_get_context_selector (tree, const char *, const char *);
+extern void c_omp_mark_declare_variant (location_t, tree, tree);
+extern int c_omp_context_selector_matches (tree);
/* Return next tree in the chain for chain_next walking of tree nodes. */
static inline tree
#include "omp-general.h"
#include "gomp-constants.h"
#include "memmodel.h"
+#include "attribs.h"
+#include "gimplify.h"
+#include "cgraph.h"
+#include "symbol-summary.h"
+#include "hsa-common.h"
/* Complete a #pragma oacc wait construct. LOC is the location of
}
/* From context selector CTX, return trait-selector with name SEL in
- trait-selector-set with name SET if any, or NULL_TREE if not found. */
+ trait-selector-set with name SET if any, or NULL_TREE if not found.
+ If SEL is NULL, return the list of trait-selectors in SET. */
tree
c_omp_get_context_selector (tree ctx, const char *set, const char *sel)
{
tree setid = get_identifier (set);
- tree selid = get_identifier (sel);
+ tree selid = sel ? get_identifier (sel) : NULL_TREE;
for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
if (TREE_PURPOSE (t1) == setid)
- for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
- if (TREE_PURPOSE (t2) == selid)
- return t2;
+ {
+ if (sel == NULL)
+ return TREE_VALUE (t1);
+ for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
+ if (TREE_PURPOSE (t2) == selid)
+ return t2;
+ }
return NULL_TREE;
}
+
+/* Register VARIANT as variant of some base function marked with
+ #pragma omp declare variant. CONSTRUCT is corresponding construct
+ selector set. */
+
+void
+c_omp_mark_declare_variant (location_t loc, tree variant, tree construct)
+{
+ tree attr = lookup_attribute ("omp declare variant variant",
+ DECL_ATTRIBUTES (variant));
+ if (attr == NULL_TREE)
+ {
+ attr = tree_cons (get_identifier ("omp declare variant variant"),
+ unshare_expr (construct),
+ DECL_ATTRIBUTES (variant));
+ 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%> "
+ "selector sets", variant);
+}
+
+/* Return 1 if context selector matches the current OpenMP context, 0
+ if it does not and -1 if it is unknown and need to be determined later.
+ Some properties can be checked right away during parsing (this routine),
+ others need to wait until the whole TU is parsed, others need to wait until
+ IPA, others until vectorization. */
+
+int
+c_omp_context_selector_matches (tree ctx)
+{
+ int ret = 1;
+ for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
+ {
+ char set = IDENTIFIER_POINTER (TREE_PURPOSE (t1))[0];
+ if (set == 'c')
+ {
+ /* For now, ignore the construct set. While something can be
+ determined already during parsing, we don't know until end of TU
+ whether additional constructs aren't added through declare variant
+ unless "omp declare variant variant" attribute exists already
+ (so in most of the cases), and we'd need to maintain set of
+ surrounding OpenMP constructs, which is better handled during
+ gimplification. */
+ ret = -1;
+ continue;
+ }
+ for (tree t2 = TREE_VALUE (t1); t2; t2 = TREE_CHAIN (t2))
+ {
+ const char *sel = IDENTIFIER_POINTER (TREE_PURPOSE (t2));
+ switch (*sel)
+ {
+ case 'v':
+ if (set == 'i' && !strcmp (sel, "vendor"))
+ for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+ {
+ const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
+ if (!strcmp (prop, " score") || !strcmp (prop, "gnu"))
+ continue;
+ return 0;
+ }
+ break;
+ case 'e':
+ if (set == 'i' && !strcmp (sel, "extension"))
+ /* We don't support any extensions right now. */
+ return 0;
+ break;
+ case 'a':
+ if (set == 'i' && !strcmp (sel, "atomic_default_mem_order"))
+ {
+ enum omp_memory_order omo
+ = ((enum omp_memory_order)
+ (omp_requires_mask
+ & OMP_REQUIRES_ATOMIC_DEFAULT_MEM_ORDER));
+ if (omo == OMP_MEMORY_ORDER_UNSPECIFIED)
+ {
+ /* We don't know yet, until end of TU. */
+ ret = -1;
+ break;
+ }
+ tree t3 = TREE_VALUE (t2);
+ const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
+ if (!strcmp (prop, " score"))
+ {
+ t3 = TREE_CHAIN (t3);
+ prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
+ }
+ if (!strcmp (prop, "relaxed")
+ && omo != OMP_MEMORY_ORDER_RELAXED)
+ return 0;
+ else if (!strcmp (prop, "seq_cst")
+ && omo != OMP_MEMORY_ORDER_SEQ_CST)
+ return 0;
+ else if (!strcmp (prop, "acq_rel")
+ && omo != OMP_MEMORY_ORDER_ACQ_REL)
+ return 0;
+ }
+ if (set == 'd' && !strcmp (sel, "arch"))
+ /* For now, need a target hook. */
+ ret = -1;
+ break;
+ case 'u':
+ if (set == 'i' && !strcmp (sel, "unified_address"))
+ {
+ if ((omp_requires_mask & OMP_REQUIRES_UNIFIED_ADDRESS) == 0)
+ ret = -1;
+ break;
+ }
+ if (set == 'i' && !strcmp (sel, "unified_shared_memory"))
+ {
+ if ((omp_requires_mask
+ & OMP_REQUIRES_UNIFIED_SHARED_MEMORY) == 0)
+ ret = -1;
+ break;
+ }
+ break;
+ case 'd':
+ if (set == 'i' && !strcmp (sel, "dynamic_allocators"))
+ {
+ if ((omp_requires_mask
+ & OMP_REQUIRES_DYNAMIC_ALLOCATORS) == 0)
+ ret = -1;
+ break;
+ }
+ break;
+ case 'r':
+ if (set == 'i' && !strcmp (sel, "reverse_offload"))
+ {
+ if ((omp_requires_mask & OMP_REQUIRES_REVERSE_OFFLOAD) == 0)
+ ret = -1;
+ break;
+ }
+ break;
+ case 'k':
+ if (set == 'd' && !strcmp (sel, "kind"))
+ for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+ {
+ const char *prop = IDENTIFIER_POINTER (TREE_PURPOSE (t3));
+ if (!strcmp (prop, "any"))
+ continue;
+ if (!strcmp (prop, "fpga"))
+ return 0; /* Right now GCC doesn't support any fpgas. */
+ if (!strcmp (prop, "host"))
+ {
+ if (ENABLE_OFFLOADING || hsa_gen_requested_p ())
+ ret = -1;
+ continue;
+ }
+ if (!strcmp (prop, "nohost"))
+ {
+ if (ENABLE_OFFLOADING || hsa_gen_requested_p ())
+ ret = -1;
+ else
+ return 0;
+ continue;
+ }
+ if (!strcmp (prop, "cpu") || !strcmp (prop, "gpu"))
+ {
+ bool maybe_gpu = false;
+ if (hsa_gen_requested_p ())
+ maybe_gpu = true;
+ else if (ENABLE_OFFLOADING)
+ for (const char *c = getenv ("OFFLOAD_TARGET_NAMES");
+ c; )
+ {
+ if (!strncmp (c, "nvptx", strlen ("nvptx"))
+ || !strncmp (c, "amdgcn", strlen ("amdgcn")))
+ {
+ maybe_gpu = true;
+ break;
+ }
+ else if ((c = strchr (c, ',')))
+ c++;
+ }
+ if (!maybe_gpu)
+ {
+ if (prop[0] == 'g')
+ return 0;
+ }
+ else
+ ret = -1;
+ continue;
+ }
+ /* Any other kind doesn't match. */
+ return 0;
+ }
+ break;
+ case 'i':
+ if (set == 'd' && !strcmp (sel, "isa"))
+ /* For now, need a target hook. */
+ ret = -1;
+ break;
+ case 'c':
+ if (set == 'u' && !strcmp (sel, "condition"))
+ for (tree t3 = TREE_VALUE (t2); t3; t3 = TREE_CHAIN (t3))
+ if (TREE_PURPOSE (t3) == NULL_TREE
+ && integer_zerop (TREE_VALUE (t3)))
+ return 0;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+ return ret;
+}
+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * c-parser.c (c_parser_omp_context_selector): Improve error recovery.
+ For simd properties, put them directly into TREE_VALUE.
+ (c_finish_omp_declare_variant): Call c_omp_mark_declare_variant.
+ If c_omp_context_selector_matches is 0, don't add attribute, otherwise
+ add "omp declare variant base" attribute rather than
+ "omp declare variant".
+
2019-10-11 Joseph Myers <joseph@codesourcery.com>
* c-decl.c (declspecs_add_type): Use pedwarn_c11 for DFP types.
else
properties = tree_cons (NULL_TREE, t, properties);
}
+ else
+ return error_mark_node;
if (c_parser_next_token_is (parser, CPP_COMMA))
c_parser_consume_token (parser);
else
properties = tree_cons (NULL_TREE, t, properties);
}
+ else
+ return error_mark_node;
break;
case CTX_PROPERTY_SIMD:
if (parms == NULL_TREE)
== error_mark_node
? NULL_TREE : parms,
c);
- properties = tree_cons (NULL_TREE, c, properties);
+ properties = c;
break;
default:
gcc_unreachable ();
}
/* Finalize #pragma omp declare variant after FNDECL has been parsed, and put
- that into "omp declare variant" attribute. */
+ that into "omp declare variant base" attribute. */
static void
c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
if (variant != error_mark_node)
{
C_DECL_USED (variant) = 1;
- tree attr = tree_cons (get_identifier ("omp declare variant"),
- build_tree_list (variant, ctx),
- DECL_ATTRIBUTES (fndecl));
- DECL_ATTRIBUTES (fndecl) = attr;
+ tree construct = c_omp_get_context_selector (ctx, "construct", NULL);
+ c_omp_mark_declare_variant (match_loc, variant, construct);
+ if (c_omp_context_selector_matches (ctx))
+ {
+ tree attr
+ = tree_cons (get_identifier ("omp declare variant base"),
+ build_tree_list (variant, ctx),
+ DECL_ATTRIBUTES (fndecl));
+ DECL_ATTRIBUTES (fndecl) = attr;
+ }
}
}
/* Finalize #pragma omp declare simd or #pragma omp declare variant
clauses after FNDECL has been parsed, and put that into "omp declare simd"
- or "omp declare variant" attribute. */
+ or "omp declare variant base" attribute. */
static void
c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * parser.c (cp_parser_omp_context_selector): Improve error recovery.
+ For simd properties, put them directly into TREE_VALUE.
+ (cp_finish_omp_declare_variant): Add "omp declare variant base"
+ attribute rather than "omp declare variant".
+
2019-10-11 Marek Polacek <polacek@redhat.com>
PR c++/92049 - extra error with -fchecking=2.
else
properties = tree_cons (NULL_TREE, t, properties);
}
+ else
+ return error_mark_node;
if (cp_lexer_next_token_is (parser->lexer, CPP_COMMA))
cp_lexer_consume_token (parser->lexer);
else
properties = tree_cons (NULL_TREE, t, properties);
}
+ else
+ return error_mark_node;
break;
case CTX_PROPERTY_SIMD:
if (!has_parms_p)
"%<metadirective%>");
return error_mark_node;
}
- tree c;
- c = cp_parser_omp_all_clauses (parser,
+ properties
+ = cp_parser_omp_all_clauses (parser,
OMP_DECLARE_SIMD_CLAUSE_MASK,
"simd", NULL, true, true);
- properties = tree_cons (NULL_TREE, c, properties);
break;
default:
gcc_unreachable ();
}
/* Finalize #pragma omp declare variant after a fndecl has been parsed, and put
- that into "omp declare variant" attribute. */
+ that into "omp declare variant base" attribute. */
static tree
cp_finish_omp_declare_variant (cp_parser *parser, cp_token *pragma_tok,
ctx = c_omp_check_context_selector (match_loc, ctx);
if (ctx != error_mark_node && variant != error_mark_node)
{
- attrs = tree_cons (get_identifier ("omp declare variant"),
+ attrs = tree_cons (get_identifier ("omp declare variant base"),
build_tree_list (variant, ctx), attrs);
if (processing_template_decl)
ATTR_IS_DEPENDENT (attrs) = 1;
+2019-10-12 Jakub Jelinek <jakub@redhat.com>
+
+ * c-c++-common/gomp/declare-variant-2.c: Adjust for error recovery
+ improvements. Add new tests.
+ * c-c++-common/gomp/declare-variant-4.c: New test.
+ * c-c++-common/gomp/declare-variant-5.c: New test.
+ * c-c++-common/gomp/declare-variant-6.c: New test.
+ * c-c++-common/gomp/declare-variant-7.c: New test.
+
2019-10-11 Joseph Myers <joseph@codesourcery.com>
* gcc.dg/dfp/c11-constants-1.c, gcc.dg/dfp/c11-constants-2.c,
+void f0 (void);
void f1 (void);
#pragma omp declare variant /* { dg-error "expected '\\(' before end of line" } */
void f2 (void);
#pragma omp declare variant (f1) match(user={condition}) /* { dg-error "expected '\\(' before '\\\}' token" } */
void f18 (void);
#pragma omp declare variant (f1) match(user={condition(}) /* { dg-error "expected \[^\n\r]*expression before '\\\}' token" } */
-void f19 (void); /* { dg-error "expected '\\)' before '\\\}' token" "" { target c++ } .-1 } */
+void f19 (void);
#pragma omp declare variant (f1) match(user={condition()}) /* { dg-error "expected \[^\n\r]*expression before '\\)' token" } */
void f20 (void);
#pragma omp declare variant (f1) match(user={condition(f1)}) /* { dg-error "property must be constant integer expression" "" { target { c || c++11 } } } */
/* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-2 } */
#pragma omp declare variant (f1) match(construct={parallel(1)}) /* { dg-error "selector 'parallel' does not accept any properties" } */
void f26 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
-#pragma omp declare variant (f1) match(construct={simd(12)}) /* { dg-error "expected \[^\n\r]* clause before" } */
+#pragma omp declare variant (f0) match(construct={simd(12)}) /* { dg-error "expected \[^\n\r]* clause before" } */
void f27 (void); /* { dg-error "'\\)' before numeric constant" "" { target c++ } .-1 } */
#pragma omp declare variant (f1) match(construct={parallel},construct={for}) /* { dg-error "selector set 'construct' specified more than once" } */
void f28 (void);
void f59 (void); /* { dg-error "expected '\\\}' before '\\(' token" "" { target c } .-1 } */
#pragma omp declare variant (f1) match(construct={parallel},foobar={bar}) /* { dg-error "expected 'construct', 'device', 'implementation' or 'user' before 'foobar'" } */
void f60 (void);
+#pragma omp declare variant (f1) match(construct={parallel,parallel}) /* { dg-error "selector 'parallel' specified more than once in set 'construct'" } */
+void f61 (void);
+#pragma omp declare variant (f1) match(construct={target,parallel,for,simd,parallel}) /* { dg-error "selector 'parallel' specified more than once in set 'construct'" } */
+void f62 (void);
+#pragma omp declare variant (f1) match(construct={target,teams,teams}) /* { dg-error "selector 'teams' specified more than once in set 'construct'" } */
+void f63 (void);
+#pragma omp declare variant (f1) match(construct={single}) /* { dg-error "selector 'single' not allowed for context selector set 'construct'" } */
+void f64 (void);
+#pragma omp declare variant (f1) match(construct={taskgroup}) /* { dg-error "selector 'taskgroup' not allowed for context selector set 'construct'" } */
+void f65 (void);
+#pragma omp declare variant (f1) match(construct={do}) /* { dg-error "selector 'do' not allowed for context selector set 'construct'" } */
+void f66 (void);
+#pragma omp declare variant (f1) match(construct={threadprivate}) /* { dg-error "selector 'threadprivate' not allowed for context selector set 'construct'" } */
+void f67 (void);
+#pragma omp declare variant (f1) match(construct={critical}) /* { dg-error "selector 'critical' not allowed for context selector set 'construct'" } */
+void f68 (void);
+#pragma omp declare variant (f1) match(construct={task}) /* { dg-error "selector 'task' not allowed for context selector set 'construct'" } */
+void f69 (void);
+#pragma omp declare variant (f1) match(construct={taskloop}) /* { dg-error "selector 'taskloop' not allowed for context selector set 'construct'" } */
+void f70 (void);
+#pragma omp declare variant (f1) match(construct={sections}) /* { dg-error "selector 'sections' not allowed for context selector set 'construct'" } */
+void f71 (void);
+#pragma omp declare variant (f1) match(construct={section}) /* { dg-error "selector 'section' not allowed for context selector set 'construct'" } */
+void f72 (void);
+#pragma omp declare variant (f1) match(construct={workshare}) /* { dg-error "selector 'workshare' not allowed for context selector set 'construct'" } */
+void f73 (void);
+#pragma omp declare variant (f1) match(construct={requires}) /* { dg-error "selector 'requires' not allowed for context selector set 'construct'" } */
+void f74 (void);
--- /dev/null
+double f1 (int, long, float);
+double f2 (int, long, float);
+double f3 (int, long, float);
+double f4 (int, long, float);
+double f5 (int, long, float);
+
+#pragma omp declare variant (f1) match (user={condition(1)})
+#pragma omp declare variant (f2) match (user={condition(score(1):1)})
+#pragma omp declare variant (f3) match (user={condition(score(3):1)})
+#pragma omp declare variant (f4) match (user={condition(score(2):1)})
+#pragma omp declare variant (f5) match (implementation={vendor(gnu)})
+double
+f6 (int x, long y, float z)
+{
+ return z + x + y;
+}
+
+double
+test (int x)
+{
+ return f6 (x, x, 3.5f);
+}
--- /dev/null
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-additional-options "-mavx2" } */
+
+typedef float __v4sf __attribute__((vector_size (16)));
+typedef int __v4si __attribute__((vector_size (16)));
+typedef float __v8sf __attribute__((vector_size (32)));
+typedef int __v8si __attribute__((vector_size (32)));
+__v4si f1 (__v4sf, __v4sf, float *);
+__v8si f2 (__v8sf, __v8sf, float *);
+__v4si f3 (__v4si, int, __v4si);
+
+#pragma omp declare variant (f1) match (construct={parallel,for,simd(simdlen(4),notinbranch,uniform(z),aligned(z:4 * sizeof (*z)))})
+#pragma omp declare variant (f2) match (construct={for,simd(uniform(z),simdlen(8),notinbranch)})
+int f4 (float x, float y, float *z);
+
+#pragma omp declare variant (f3) match (construct={simd(simdlen(4),inbranch,linear(y:1))})
+int f5 (int x, int y);
+
+void
+test (int *x, float *y, float *z, float *w)
+{
+ #pragma omp parallel
+ #pragma omp for simd aligned (w:4 * sizeof (float))
+ for (int i = 0; i < 1024; i++)
+ x[i] = f4 (y[i], z[i], w);
+ #pragma omp parallel for simd aligned (w:4 * sizeof (float)) simdlen(4)
+ for (int i = 1024; i < 2048; i++)
+ x[i] = f4 (y[i], z[i], w);
+ #pragma omp simd aligned (w:4 * sizeof (float))
+ for (int i = 2048; i < 4096; i++)
+ x[i] = f4 (y[i], z[i], w);
+ #pragma omp simd
+ for (int i = 4096; i < 8192; i++)
+ if (x[i] > 10)
+ x[i] = f5 (x[i], i);
+}
--- /dev/null
+double f1 (int, long, float);
+double f2 (int, long, float);
+#pragma omp declare variant (f1) match (user={condition(0)},construct={parallel})
+double f3 (int, long, float);
+#pragma omp declare variant (f1) match (construct={parallel},user={condition(score(1):1)})
+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 "'f5' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+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 "'f8' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+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 "'f11' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+double f14 (int, long, float);
+#pragma omp declare variant (f11) match (device={kind(any)},construct={teams,parallel}) /* { dg-error "'f11' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+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 "'f16' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+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 "'f19' used as a variant with incompatible 'constructor' selector sets" "" { target c } } */
+double f21 (int, long, float);
--- /dev/null
+/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
+/* { dg-additional-options "-mavx2" } */
+
+typedef float __v4sf __attribute__((vector_size (16)));
+typedef int __v4si __attribute__((vector_size (16)));
+typedef float __v8sf __attribute__((vector_size (32)));
+typedef int __v8si __attribute__((vector_size (32)));
+__v4si f1 (__v4sf, __v4sf, float *);
+__v8si f2 (__v8sf, __v8sf, float *);
+__v4si f3 (__v4si, int, __v4si);
+
+#pragma omp declare variant (f1) match (construct={parallel,for,simd(simdlen(4),notinbranch,uniform(z),aligned(z:4 * sizeof (*z)))})
+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 } } */
+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 } } */
+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 } } */
+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 } } */
+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 } } */
+int f14 (int x, int q);