@@ -719,6 +719,12 @@ decl_attributes (tree *node, tree attrib
if (ns == NULL_TREE || !cxx11_attr_p)
warning (OPT_Wattributes, "%qE attribute directive ignored",
name);
+ else if ((flag_openmp || flag_openmp_simd)
+ && is_attribute_p ("omp", ns)
+ && is_attribute_p ("directive", name)
+ && (VAR_P (*node)
+ || TREE_CODE (*node) == FUNCTION_DECL))
+ continue;
else
warning (OPT_Wattributes,
"%<%E::%E%> scoped attribute directive ignored",
@@ -3306,6 +3306,8 @@ const struct c_omp_directive c_omp_direc
C_OMP_DIR_STANDALONE, false },
{ "for", nullptr, nullptr, PRAGMA_OMP_FOR,
C_OMP_DIR_CONSTRUCT, true },
+ /* { "groupprivate", nullptr, nullptr, PRAGMA_OMP_GROUPPRIVATE,
+ C_OMP_DIR_DECLARATIVE, false }, */
/* { "interop", nullptr, nullptr, PRAGMA_OMP_INTEROP,
C_OMP_DIR_STANDALONE, false }, */
{ "loop", nullptr, nullptr, PRAGMA_OMP_LOOP,
@@ -107,6 +107,10 @@ struct GTY (()) cp_lexer {
/* The next lexer in a linked list of lexers. */
struct cp_lexer *next;
+ /* Set for omp::decl attribute parsing to the decl to which it
+ appertains. */
+ tree in_omp_decl_attribute;
+
/* True if we should output debugging information. */
bool debugging_p;
@@ -7317,6 +7317,7 @@ extern tree cp_convert_range_for (tree,
extern void cp_convert_omp_range_for (tree &, tree &, tree &,
tree &, tree &, tree &, tree &, tree &);
extern void cp_finish_omp_range_for (tree, tree);
+extern bool cp_maybe_parse_omp_decl (tree, tree);
extern bool parsing_nsdmi (void);
extern bool parsing_function_declarator ();
extern bool parsing_default_capturing_generic_lambda_in_template (void);
@@ -12001,6 +12001,12 @@ cp_parser_handle_statement_omp_attribute
parser->omp_attrs_forbidden_p = false;
bad = true;
}
+ else if (TREE_PUBLIC (d))
+ {
+ error_at (first->location,
+ "OpenMP %<omp::decl%> attribute on a statement");
+ bad = true;
+ }
const char *directive[3] = {};
for (int i = 0; i < 3; i++)
{
@@ -12022,8 +12028,9 @@ cp_parser_handle_statement_omp_attribute
if (dir == NULL)
{
error_at (first->location,
- "unknown OpenMP directive name in %<omp::directive%>"
- " attribute argument");
+ "unknown OpenMP directive name in %qs attribute "
+ "argument",
+ TREE_PUBLIC (d) ? "omp::decl" : "omp::directive");
continue;
}
c_omp_directive_kind kind = dir->kind;
@@ -29366,7 +29373,7 @@ cp_parser_gnu_attribute_list (cp_parser*
parsing. */
static void
-cp_parser_omp_directive_args (cp_parser *parser, tree attribute)
+cp_parser_omp_directive_args (cp_parser *parser, tree attribute, bool decl_p)
{
cp_token *first = cp_lexer_peek_nth_token (parser->lexer, 2);
if (first->type == CPP_CLOSE_PAREN)
@@ -29393,6 +29400,8 @@ cp_parser_omp_directive_args (cp_parser
tree arg = make_node (DEFERRED_PARSE);
DEFPARSE_TOKENS (arg) = cp_token_cache_new (first, last);
DEFPARSE_INSTANTIATIONS (arg) = nullptr;
+ if (decl_p)
+ TREE_PUBLIC (arg) = 1;
TREE_VALUE (attribute) = tree_cons (NULL_TREE, arg, TREE_VALUE (attribute));
}
@@ -29440,7 +29449,7 @@ cp_parser_omp_sequence_args (cp_parser *
cp_parser_required_error (parser, RT_OPEN_PAREN, false,
UNKNOWN_LOCATION);
else if (directive)
- cp_parser_omp_directive_args (parser, attribute);
+ cp_parser_omp_directive_args (parser, attribute, false);
else
cp_parser_omp_sequence_args (parser, attribute);
if (cp_lexer_next_token_is_not (parser->lexer, CPP_COMMA))
@@ -29592,7 +29601,8 @@ cp_parser_std_attribute (cp_parser *pars
if ((flag_openmp || flag_openmp_simd)
&& attr_ns == omp_identifier
&& (is_attribute_p ("directive", attr_id)
- || is_attribute_p ("sequence", attr_id)))
+ || is_attribute_p ("sequence", attr_id)
+ || is_attribute_p ("decl", attr_id)))
{
error_at (token->location, "%<omp::%E%> attribute requires argument",
attr_id);
@@ -29636,7 +29646,14 @@ cp_parser_std_attribute (cp_parser *pars
{
if (is_attribute_p ("directive", attr_id))
{
- cp_parser_omp_directive_args (parser, attribute);
+ cp_parser_omp_directive_args (parser, attribute, false);
+ return attribute;
+ }
+ else if (is_attribute_p ("decl", attr_id))
+ {
+ TREE_VALUE (TREE_PURPOSE (attribute))
+ = get_identifier ("directive");
+ cp_parser_omp_directive_args (parser, attribute, true);
return attribute;
}
else if (is_attribute_p ("sequence", attr_id))
@@ -37912,6 +37929,21 @@ static tree
cp_parser_omp_var_list (cp_parser *parser, enum omp_clause_code kind, tree list,
bool allow_deref = false)
{
+ if (parser->lexer->in_omp_decl_attribute)
+ {
+ if (kind)
+ {
+ location_t loc = cp_lexer_peek_token (parser->lexer)->location;
+ tree u = build_omp_clause (loc, kind);
+ OMP_CLAUSE_DECL (u) = parser->lexer->in_omp_decl_attribute;
+ OMP_CLAUSE_CHAIN (u) = list;
+ return u;
+ }
+ else
+ return tree_cons (parser->lexer->in_omp_decl_attribute, NULL_TREE,
+ list);
+ }
+
if (cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
return cp_parser_omp_var_list_no_open (parser, kind, list, NULL,
allow_deref);
@@ -47843,7 +47875,9 @@ cp_parser_late_parsing_omp_declare_simd
{
error_at (first->location,
"unknown OpenMP directive name in "
- "%<omp::directive%> attribute argument");
+ "%qs attribute argument",
+ TREE_PUBLIC (d)
+ ? "omp::decl" : "omp::directive");
continue;
}
if (dir->id != PRAGMA_OMP_DECLARE
@@ -47949,6 +47983,89 @@ cp_parser_late_parsing_omp_declare_simd
return attrs;
}
+/* D should be DEFERRED_PARSE from omp::decl attribute. If it contains
+ a threadprivate, groupprivate, allocate or declare target directive,
+ return true and parse it for DECL. */
+
+bool
+cp_maybe_parse_omp_decl (tree decl, tree d)
+{
+ gcc_assert (TREE_CODE (d) == DEFERRED_PARSE);
+ cp_token *first = DEFPARSE_TOKENS (d)->first;
+ cp_token *last = DEFPARSE_TOKENS (d)->last;
+ const char *directive[3] = {};
+ for (int j = 0; j < 3; j++)
+ {
+ tree id = NULL_TREE;
+ if (first + j == last)
+ break;
+ if (first[j].type == CPP_NAME)
+ id = first[j].u.value;
+ else if (first[j].type == CPP_KEYWORD)
+ id = ridpointers[(int) first[j].keyword];
+ else
+ break;
+ directive[j] = IDENTIFIER_POINTER (id);
+ }
+ const c_omp_directive *dir = NULL;
+ if (directive[0])
+ dir = c_omp_categorize_directive (directive[0], directive[1],
+ directive[2]);
+ if (dir == NULL)
+ {
+ error_at (first->location,
+ "unknown OpenMP directive name in "
+ "%qs attribute argument", "omp::decl");
+ return false;
+ }
+ if (dir->id != PRAGMA_OMP_THREADPRIVATE
+ /* && dir->id != PRAGMA_OMP_GROUPPRIVATE */
+ && dir->id != PRAGMA_OMP_ALLOCATE
+ && (dir->id != PRAGMA_OMP_DECLARE
+ || strcmp (directive[1], "target") != 0))
+ return false;
+
+ if (!flag_openmp && !dir->simd)
+ return true;
+
+ cp_parser *parser = the_parser;
+ cp_lexer *lexer = cp_lexer_alloc ();
+ lexer->debugging_p = parser->lexer->debugging_p;
+ lexer->in_omp_decl_attribute = decl;
+ vec_safe_reserve (lexer->buffer, last - first + 3, true);
+ cp_token tok = {};
+ tok.type = CPP_PRAGMA;
+ tok.keyword = RID_MAX;
+ tok.u.value = build_int_cst (NULL, dir->id);
+ tok.location = first->location;
+ lexer->buffer->quick_push (tok);
+ while (++first < last)
+ lexer->buffer->quick_push (*first);
+ tok = {};
+ tok.type = CPP_PRAGMA_EOL;
+ tok.keyword = RID_MAX;
+ tok.location = last->location;
+ lexer->buffer->quick_push (tok);
+ tok = {};
+ tok.type = CPP_EOF;
+ tok.keyword = RID_MAX;
+ tok.location = last->location;
+ lexer->buffer->quick_push (tok);
+ lexer->next = parser->lexer;
+ lexer->next_token = lexer->buffer->address ();
+ lexer->last_token = lexer->next_token
+ + lexer->buffer->length ()
+ - 1;
+ lexer->in_omp_attribute_pragma = true;
+ parser->lexer = lexer;
+ /* Move the current source position to that of the first token in the
+ new lexer. */
+ cp_lexer_set_source_position_from_token (lexer->next_token);
+ cp_parser_pragma (parser, pragma_external, NULL);
+
+ return true;
+}
+
/* Helper for cp_parser_omp_declare_target, handle one to or link clause
on #pragma omp declare target. Return false if errors were reported. */
@@ -48048,7 +48165,8 @@ cp_parser_omp_declare_target (cp_parser
clauses
= cp_parser_omp_all_clauses (parser, OMP_DECLARE_TARGET_CLAUSE_MASK,
"#pragma omp declare target", pragma_tok);
- else if (cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
+ else if (parser->lexer->in_omp_decl_attribute
+ || cp_lexer_next_token_is (parser->lexer, CPP_OPEN_PAREN))
{
clauses = cp_parser_omp_var_list (parser, OMP_CLAUSE_ENTER,
clauses);
@@ -1738,16 +1738,34 @@ cplus_decl_attributes (tree *decl, tree
{
tree name = get_attribute_name (*pa);
if (is_attribute_p ("directive", name)
- || is_attribute_p ("sequence", name))
+ || is_attribute_p ("sequence", name)
+ || is_attribute_p ("decl", name))
{
- if (!diagnosed)
+ const char *p = NULL;
+ if (TREE_VALUE (*pa) == NULL_TREE)
+ p = IDENTIFIER_POINTER (name);
+ for (tree a = TREE_VALUE (*pa); a; a = TREE_CHAIN (a))
{
- error ("%<omp::%E%> not allowed to be specified in this "
- "context", name);
+ tree d = TREE_VALUE (a);
+ gcc_assert (TREE_CODE (d) == DEFERRED_PARSE);
+ if (TREE_PUBLIC (d)
+ && (VAR_P (*decl)
+ || TREE_CODE (*decl) == FUNCTION_DECL)
+ && cp_maybe_parse_omp_decl (*decl, d))
+ continue;
+ p = TREE_PUBLIC (d) ? "decl" : "directive";
+ }
+ if (p && !diagnosed)
+ {
+ error ("%<omp::%s%> not allowed to be specified in "
+ "this context", p);
diagnosed = true;
}
- *pa = TREE_CHAIN (*pa);
- continue;
+ if (p)
+ {
+ *pa = TREE_CHAIN (*pa);
+ continue;
+ }
}
}
pa = &TREE_CHAIN (*pa);
@@ -8402,12 +8402,24 @@ finish_using_directive (tree target, tre
else if ((flag_openmp || flag_openmp_simd)
&& get_attribute_namespace (a) == omp_identifier
&& (is_attribute_p ("directive", name)
- || is_attribute_p ("sequence", name)))
+ || is_attribute_p ("sequence", name)
+ || is_attribute_p ("decl", name)))
{
if (!diagnosed)
- error ("%<omp::%E%> not allowed to be specified in this "
- "context", name);
- diagnosed = true;
+ {
+ if (tree ar = TREE_VALUE (a))
+ {
+ tree d = TREE_VALUE (ar);
+ gcc_assert (TREE_CODE (d) == DEFERRED_PARSE);
+ error ("%<omp::%s%> not allowed to be specified in "
+ "this context",
+ TREE_PUBLIC (d) ? "decl" : "directive");
+ }
+ else
+ error ("%<omp::%E%> not allowed to be specified in this "
+ "context", name);
+ diagnosed = true;
+ }
}
else
warning (OPT_Wattributes, "%qD attribute directive ignored", name);
@@ -0,0 +1,68 @@
+// { dg-do compile { target c++11 } }
+
+void foo1 ();
+
+void
+foo ()
+{
+ [[omp::decl (declare variant (foo1) match (construct={parallel,for}))]]
+ extern void foo2 ();
+ [[omp::sequence (directive (parallel), directive (for))]]
+ for (int i = 0; i < 5; i++)
+ foo2 ();
+ [[omp::decl (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch),
+ omp::directive (declare simd simdlen(8) notinbranch)]]
+ extern int foo3 (int l, int *p);
+ [[omp::directive (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch),
+ omp::decl (declare simd simdlen(8) notinbranch)]]
+ extern int foo4 (int l, int *p);
+ [[omp::decl (declare simd simdlen(4) linear(l) aligned(p:4) uniform(p) inbranch),
+ omp::decl (declare simd simdlen(8) notinbranch)]]
+ extern int foo5 (int l, int *p);
+}
+
+void bar1 ();
+
+void
+bar ()
+{
+ [[using omp : decl (declare variant (bar1), match (construct={parallel,for}))]] // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+ extern void bar2 ();
+ [[using omp : sequence (directive (parallel), directive (for))]] // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+ for (int i = 0; i < 5; i++)
+ bar2 ();
+ [[omp::decl (declare simd, simdlen(4), linear(l), aligned(p:4),uniform(p),inbranch),
+ omp::directive (declare simd simdlen(8) notinbranch)]]
+ extern int bar3 (int l, int *p);
+ [[using omp : directive (declare simd,simdlen(4),linear(l),aligned(p:4),uniform(p),inbranch), // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+ decl (declare simd, simdlen(8), notinbranch)]]
+ extern int bar4 (int l, int *p);
+ [[omp::decl (declare simd, simdlen(4), linear(l), aligned(p:4), uniform(p), inbranch),
+ omp::decl (declare simd, simdlen(8), notinbranch)]]
+ extern int bar5 (int l, int *p);
+}
+
+struct S { S (); ~S (); int s; };
+
+[[omp::decl (threadprivate)]] int t1, t2;
+int x1, t3 [[omp::decl (threadprivate)]], x2, t4 [[omp::decl (threadprivate)]] [5];
+[[maybe_unused, omp::decl (threadprivate)]] int t5, t6;
+[[using omp : decl (threadprivate)]] S t7, t8; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+[[using omp : decl (declare target enter device_type (host))]] int d1, d2, d3 (int, int), d4; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+int x3, d5 [[omp::decl (declare target, enter, device_type (any))]], d6 [[omp::decl (declare target link)]], x4;
+int d7 [[omp::decl (declare target)]];
+[[using omp : decl (declare target), decl (declare target)]] int d8, d9; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+
+void
+baz ()
+{
+ [[omp::decl (threadprivate)]] static int t1, t2;
+ static int x1, t3 [[omp::decl (threadprivate)]], x2, t4 [[omp::decl (threadprivate)]] [5];
+ [[maybe_unused, omp::decl (threadprivate)]] extern int t5, t6;
+ [[using omp : decl (declare target enter)]] extern int d1, d2, d3 (int, int), d4; // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+ static int x3, d5 [[omp::decl (declare target, enter, device_type (any))]], d6 [[omp::decl (declare target link)]], x4;
+ ++t1; ++t2;
+ ++t3; ++t4[2];
+ ++t5; ++t6;
+ ++d1;
+}
@@ -0,0 +1,240 @@
+// { dg-do compile { target c++11 } }
+// { dg-options "-fopenmp -ffat-lto-objects -fdump-tree-gimple" }
+
+extern "C" void abort ();
+
+[[omp::decl (declare simd, linear (l))]] extern int f1 (int l);
+extern int f2 (int), f3 [[omp::decl (declare simd, uniform (m))]] (int m), f4 (int), z;
+[[omp::decl (declare simd, linear (l), simdlen(4))]] extern int f5 [[omp::decl (declare simd uniform (l) simdlen (8) notinbranch)]] (int l);
+
+int
+f1 (int l)
+{
+ return l;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16l__Z2f1i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f2 (int l)
+{
+ return l + 1;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f2i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f3 (int l)
+{
+ return l + 2;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16u__Z2f3i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f4 (int l)
+{
+ return l + 3;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f4i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f5 (int l)
+{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-1 }
+ return l + 4;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f5i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f5i:" { target { i?86-*-* x86_64-*-* } } } }
+
+[[omp::decl (declare simd, linear (l), simdlen(4), notinbranch),
+ omp::decl (declare simd, uniform (l), simdlen(4), inbranch)]]
+int
+f6 [[using omp : decl (declare simd uniform (l) simdlen (8), notinbranch), // { dg-warning "attribute using prefix only available with" "" { target c++14_down } }
+ decl (declare simd, linear (l), simdlen (8), inbranch)]] (int l)
+{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-2 }
+ return l + 5;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM8l__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f6i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M4l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]N4u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]M8u__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-not "_ZGV\[bcde]N8l__Z2f6i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f7 (int l)
+{
+ return l + 6;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f7i:" { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f8 (int l)
+{
+ return l + 7;
+}
+
+// { dg-final { scan-assembler-not "_ZGV\[a-zA-Z0-9]__Z2f8i:" { target { i?86-*-* x86_64-*-* } } } }
+
+[[omp::decl (declare variant (f7), match (construct={parallel})),
+ omp::decl (declare simd uniform (l), simdlen(4))]]
+int
+f9 [[omp::decl (declare simd uniform (l) simdlen (8)),
+ omp::decl (declare variant (f8) match (construct={parallel,for}))]] (int l)
+{ // { dg-warning "GCC does not currently support simdlen 8 for type 'int'" "" { target aarch64*-*-* } .-2 }
+ return l + 8;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN4u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVbN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN8u__Z2f9i:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int z;
+
+void
+test ()
+{
+ [[omp::directive (parallel)]]
+ if (f9 (3) != 9)
+ abort ();
+ [[omp::directive (parallel for)]]
+ for (int i = 0; i < 1; i++)
+ if (f9 (4) != 11)
+ abort ();
+ if (f9 (5) != 13)
+ abort ();
+}
+
+// { dg-final { scan-tree-dump-times " = f7 \\\(3\\\);" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times " = f8 \\\(4\\\);" 1 "gimple" } }
+// { dg-final { scan-tree-dump-times " = f9 \\\(5\\\);" 1 "gimple" } }
+
+template <int N>
+int
+f10 (int x)
+{
+ return x + N;
+}
+
+template [[omp::decl (declare simd, notinbranch)]] int f10<0> (int);
+
+// { dg-final { scan-assembler-times "_ZGVbN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16v__Z3f10ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template int f10<1> [[omp::decl (declare simd inbranch linear(x))]] (int x);
+
+// { dg-final { scan-assembler-times "_ZGVbM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16l__Z3f10ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template <int N>
+int f11 (int);
+
+template <> [[omp::decl (declare simd, inbranch)]] int
+f11<0> (int x)
+{
+ return x;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16v__Z3f11ILi0EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+template <> int
+f11<1> [[omp::decl (declare simd, notinbranch, linear (y))]] (int y)
+{
+ return y;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16l__Z3f11ILi1EEii:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+struct S
+{
+ [[omp::decl (declare simd, inbranch, uniform (this))]] int f12 (int x);
+ int f13 [[gnu::noinline, omp::decl (declare simd notinbranch uniform (this) linear (y))]] (int y) { return y; }
+};
+
+int
+S::f12 (int x)
+{
+ return x;
+}
+
+// { dg-final { scan-assembler-times "_ZGVbM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcM4uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdM8uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeM16uv__ZN1S3f12Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+// { dg-final { scan-assembler-times "_ZGVbN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVcN4ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVdN8ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+// { dg-final { scan-assembler-times "_ZGVeN16ul__ZN1S3f13Ei:" 1 { target { i?86-*-* x86_64-*-* } } } }
+
+int
+f14 (S &p, int x)
+{
+ return p.f13 (x);
+}
@@ -0,0 +1,27 @@
+// { dg-do compile { target c++11 } }
+
+void
+foo ()
+{
+ [[omp::decl]] int v1; // { dg-error "'omp::decl' attribute requires argument" }
+ [[omp::decl ()]] int v2; // { dg-error "expected OpenMP directive name" }
+ // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 }
+ [[omp::decl (nonexistent foobar)]] int v3; // { dg-error "unknown OpenMP directive name in 'omp::decl' attribute argument" }
+ // { dg-error "'omp::decl' not allowed to be specified in this context" "" { target *-*-* } .-1 }
+ [[omp::sequence(decl(threadprivate))]] int v4; // { dg-error "expected 'directive' or 'sequence'" }
+ // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 }
+ [[omp::sequence(omp::decl(threadprivate))]] int v5; // { dg-error "expected 'directive' or 'sequence'" }
+ // { dg-error "'omp::directive' not allowed to be specified in this context" "" { target *-*-* } .-1 }
+ [[omp::decl (barrier)]]; // { dg-error "OpenMP 'omp::decl' attribute on a statement" }
+ [[omp::decl (parallel)]] {}; // { dg-error "OpenMP 'omp::decl' attribute on a statement" }
+ extern int [[omp::decl (threadprivate)]] *v6; // { dg-warning "attribute ignored" }
+ [[omp::decl (threadprivate (v5))]] static int v7; // { dg-error "expected end of line before '\\\(' token" }
+ extern int v8;
+ [[omp::decl (declare target (v8))]] static int v9; // { dg-error "expected end of line before '\\\(' token" }
+ [[omp::decl (declare target enter (v8))]] static int v10; // { dg-error "expected an OpenMP clause before '\\\(' token" }
+ [[omp::decl (declare target, link (v9))]] static int v11; // { dg-error "expected an OpenMP clause before '\\\(' token" }
+ [[omp::decl (declare target device_type (any))]] static int v12; // { dg-error "directive with only 'device_type' clause" }
+}
+
+int i;
+[[omp::decl (assume (i < 42))]]; // { dg-error "OpenMP 'omp::decl' attribute on a statement" }
@@ -444,7 +444,7 @@ Technical Report (TR) 11 is the first pr
@item Features deprecated in versions 5.2, 5.1 and 5.0 were removed
@tab N/A @tab Backward compatibility
@item The @code{decl} attribute was added to the C++ attribute syntax
- @tab N @tab
+ @tab Y @tab
@item @code{_ALL} suffix to the device-scope environment variables
@tab P @tab Host device number wrongly accepted
@item For Fortran, @emph{locator list} can be also function reference with