openmp: Add omp::decl attribute support [PR111392]

This patch adds support for (so far C++) omp::decl attribute.  For
declare simd and declare variant directives it is essentially another
spelling of omp::decl, except per discussions it is not allowed inside
of omp::sequence attribute.  For threadprivate, declare target, allocate
and later groupprivate directives it should appertain to variable (or for
declare target also function definitions and) declarations and where in
normal syntax one specifies a list of variables (or variables and functions),
either as argument of the directive or clause argument, such argument is
not specified and implied to be the variable it applies to.

2023-09-20  Jakub Jelinek  <jakub@redhat.com>

	PR c++/111392
gcc/
	* attribs.cc (decl_attributes): Don't warn on omp::directive attribute
	on vars or function decls if -fopenmp or -fopenmp-simd.
gcc/c-family/
	* c-omp.cc (c_omp_directives): Add commented out groupprivate
	directive entry.
gcc/cp/
	* parser.h (struct cp_lexer): Add in_omp_decl_attribute member.
	* cp-tree.h (cp_maybe_parse_omp_decl): Declare.
	* parser.cc (cp_parser_handle_statement_omp_attributes): Diagnose
	omp::decl attribute on statements.  Adjust diagnostic wording for
	omp::decl.
	(cp_parser_omp_directive_args): Add DECL_P argument, set TREE_PUBLIC
	to it on the DEFERRED_PARSE tree.
	(cp_parser_omp_sequence_args): Adjust caller.
	(cp_parser_std_attribute): Handle omp::decl attribute.
	(cp_parser_omp_var_list): If parser->lexer->in_omp_decl_attribute
	don't expect any arguments, instead create clause or TREE_LIST for
	that decl.
	(cp_parser_late_parsing_omp_declare_simd): Adjust diagnostic wording
	for omp::decl.
	(cp_maybe_parse_omp_decl): New function.
	(cp_parser_omp_declare_target): If
	parser->lexer->in_omp_decl_attribute and first token isn't name or
	comma invoke cp_parser_omp_var_list.
	* decl2.cc (cplus_decl_attributes): Adjust diagnostic wording for
	omp::decl.  Handle omp::decl on declarations.
	* name-lookup.cc (finish_using_directive): Adjust diagnostic wording
	for omp::decl.
gcc/testsuite/
	* g++.dg/gomp/attrs-19.C: New test.
	* g++.dg/gomp/attrs-20.C: New test.
	* g++.dg/gomp/attrs-21.C: New test.
libgomp/
	* libgomp.texi: Mark decl attribute was added to the C++ attribute
	syntax as implemented.
This commit is contained in:
Jakub Jelinek 2023-09-20 08:43:02 +02:00
parent d024a31a09
commit 04b2fb5bb6
11 changed files with 515 additions and 19 deletions

View file

@ -719,6 +719,12 @@ decl_attributes (tree *node, tree attributes, int flags,
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",

View file

@ -3306,6 +3306,8 @@ const struct c_omp_directive c_omp_directives[] = {
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,

View file

@ -7341,6 +7341,7 @@ extern tree cp_convert_range_for (tree, tree, tree, cp_decomp *, bool,
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);

View file

@ -1782,16 +1782,34 @@ cplus_decl_attributes (tree *decl, tree attributes, int flags)
{
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);

View file

@ -8402,12 +8402,24 @@ finish_using_directive (tree target, tree attribs)
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);

View file

@ -12001,6 +12001,12 @@ cp_parser_handle_statement_omp_attributes (cp_parser *parser, tree attrs)
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_attributes (cp_parser *parser, tree attrs)
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* parser, bool exactly_one /* = false */)
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 *parser, tree attribute)
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 *parser, tree attribute)
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 *parser, tree attr_ns)
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 *parser, tree attr_ns)
{
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 (cp_parser *parser, tree attrs)
{
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 (cp_parser *parser, tree attrs)
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 *parser, cp_token *pragma_tok)
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);

View file

@ -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;

View file

@ -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;
}

View file

@ -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);
}

View file

@ -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" }

View file

@ -444,7 +444,7 @@ Technical Report (TR) 11 is the first preview for OpenMP 6.0.
@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