]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add omp::decl attribute support [PR111392]
authorJakub Jelinek <jakub@redhat.com>
Wed, 20 Sep 2023 06:43:02 +0000 (08:43 +0200)
committerJakub Jelinek <jakub@redhat.com>
Wed, 20 Sep 2023 06:43:02 +0000 (08:43 +0200)
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.

gcc/attribs.cc
gcc/c-family/c-omp.cc
gcc/cp/cp-tree.h
gcc/cp/decl2.cc
gcc/cp/name-lookup.cc
gcc/cp/parser.cc
gcc/cp/parser.h
gcc/testsuite/g++.dg/gomp/attrs-19.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/attrs-20.C [new file with mode: 0644]
gcc/testsuite/g++.dg/gomp/attrs-21.C [new file with mode: 0644]
libgomp/libgomp.texi

index b8cb55b97df38498f2c912ec0132a05612b1c3dd..229d8b32c1ee0730ed4e0cdd920efe3a8c07e4a8 100644 (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",
index 9b7d7f789e3d0dfba50633f2dd686704e9f52911..95b6c1e623fb637bb7b796f976a39f4269cc1975 100644 (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,
index fd6bf9fd4a03897372251002e270adf520d16a80..6e34952da999e47d24ba2ac6931725a4cf6de70b 100644 (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);
index 5dae6f3bbc05dbd49a73d339b9e04d52f45f8605..113b03119ec131f01bc097a078fde035e753c73f 100644 (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);
index e776bb868fd8a3ff60df342daca3d10aaa24e770..a8b9229b29ec9d9678101f691a41a57d8d24fde6 100644 (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);
index 8808da3a8428e8172b6325f145cc020bf620c206..8cac3dc94b9ff759a9388a76868834c1c8037180 100644 (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);
index 6cbb9a8e031499007c3a740ef86a322bcb1c72d9..9ba802194e45c401e314be8cb547080bb5ff8159 100644 (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;
 
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-19.C b/gcc/testsuite/g++.dg/gomp/attrs-19.C
new file mode 100644 (file)
index 0000000..77e565a
--- /dev/null
@@ -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;
+}
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-20.C b/gcc/testsuite/g++.dg/gomp/attrs-20.C
new file mode 100644 (file)
index 0000000..86f8612
--- /dev/null
@@ -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);
+}
diff --git a/gcc/testsuite/g++.dg/gomp/attrs-21.C b/gcc/testsuite/g++.dg/gomp/attrs-21.C
new file mode 100644 (file)
index 0000000..46bdef2
--- /dev/null
@@ -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" }
index c6cd825bbaacb9298fd50d60be826dbe15e86725..f5cb5b643a2284dee15c3b474998b8159c6d1572 100644 (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