]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
openmp: Add C support for parsing metadirectives
authorKwok Cheung Yeung <kcy@codesourcery.com>
Tue, 25 Jan 2022 18:31:19 +0000 (10:31 -0800)
committerKwok Cheung Yeung <kcy@codesourcery.com>
Tue, 25 Jan 2022 20:04:57 +0000 (12:04 -0800)
This patch implements parsing for the OpenMP metadirective introduced in
OpenMP 5.0.  Metadirectives are parsed into an OMP_METADIRECTIVE node,
with the variant clauses forming a chain accessible via
OMP_METADIRECTIVE_CLAUSES.  Each clause contains the context selector
and tree for the variant.

User conditions in the selector are now permitted to be non-constant when
used in metadirectives as specified in OpenMP 5.1.

2021-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>

gcc/
* omp-general.c (omp_context_selector_matches): Add extra argument.
(omp_resolve_metadirective): New stub function.
* omp-general.h (struct omp_metadirective_variant): New.
(omp_context_selector_matches): Add extra argument.
(omp_resolve_metadirective): New prototype.
* tree.def (OMP_METADIRECTIVE): New.
* tree.h (OMP_METADIRECTIVE_CLAUSES): New macro.

gcc/c/
* c-parser.c (c_parser_skip_to_end_of_block_or_statement): Handle
parentheses in statement.
(c_parser_omp_metadirective): New prototype.
(c_parser_omp_context_selector): Add extra argument.  Allow
non-constant expressions.
(c_parser_omp_context_selector_specification): Add extra argument and
propagate it to c_parser_omp_context_selector.
(analyze_metadirective_body): New.
(c_parser_omp_metadirective): New.
(c_parser_omp_construct): Handle PRAGMA_OMP_METADIRECTIVE.

gcc/c-family
* c-common.h (enum c_omp_directive_kind): Add C_OMP_DIR_META.
(c_omp_expand_metadirective): New prototype.
* c-gimplify.c (genericize_omp_metadirective_stmt): New.
(c_genericize_control_stmt): Handle OMP_METADIRECTIVE tree nodes.
* c-omp.c (omp_directives): Classify metadirectives as C_OMP_DIR_META.
(c_omp_expand_metadirective): New stub function.
* c-pragma.c (omp_pragmas): Add entry for metadirective.
* c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_METADIRECTIVE.

13 files changed:
gcc/ChangeLog.omp
gcc/c-family/ChangeLog.omp
gcc/c-family/c-common.h
gcc/c-family/c-gimplify.c
gcc/c-family/c-omp.c
gcc/c-family/c-pragma.c
gcc/c-family/c-pragma.h
gcc/c/ChangeLog.omp
gcc/c/c-parser.c
gcc/omp-general.c
gcc/omp-general.h
gcc/tree.def
gcc/tree.h

index 07f31cffc35e6ed994c7bff2c3204e7486e3081d..0615ddf515f5a9cbc2912c58f6e388f3aec9a617 100644 (file)
@@ -1,3 +1,13 @@
+2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * omp-general.c (omp_context_selector_matches): Add extra argument.
+       (omp_resolve_metadirective): New stub function.
+       * omp-general.h (struct omp_metadirective_variant): New.
+       (omp_context_selector_matches): Add extra argument.
+       (omp_resolve_metadirective): New prototype.
+       * tree.def (OMP_METADIRECTIVE): New.
+       * tree.h (OMP_METADIRECTIVE_CLAUSES): New macro.
+
 2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
 
        Backport from master:
index e704d7d726178c11c99ad8ce502c9ebd8ce4a2f3..1f0e2a83ef98415c47267f38b0a42c0acc18dc14 100644 (file)
@@ -1,3 +1,14 @@
+2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * c-common.h (enum c_omp_directive_kind): Add C_OMP_DIR_META.
+       (c_omp_expand_metadirective): New prototype.
+       * c-gimplify.c (genericize_omp_metadirective_stmt): New.
+       (c_genericize_control_stmt): Handle OMP_METADIRECTIVE tree nodes.
+       * c-omp.c (omp_directives): Classify metadirectives as C_OMP_DIR_META.
+       (c_omp_expand_metadirective): New stub function.
+       * c-pragma.c (omp_pragmas): Add entry for metadirective.
+       * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_METADIRECTIVE.
+
 2021-11-10  Tobias Burnus  <tobias@codesourcery.com>
 
        Backported from master:
index 919b8740b682a9c43e69b04fc754111ddefea873..f993dab6fe4f3cfcc710e642975e642e9f0815ae 100644 (file)
@@ -1252,7 +1252,8 @@ enum c_omp_directive_kind {
   C_OMP_DIR_CONSTRUCT,
   C_OMP_DIR_DECLARATIVE,
   C_OMP_DIR_UTILITY,
-  C_OMP_DIR_INFORMATIONAL
+  C_OMP_DIR_INFORMATIONAL,
+  C_OMP_DIR_META
 };
 
 struct c_omp_directive {
@@ -1265,6 +1266,7 @@ struct c_omp_directive {
 extern const struct c_omp_directive *c_omp_categorize_directive (const char *,
                                                                 const char *,
                                                                 const char *);
+extern tree c_omp_expand_metadirective (vec<struct omp_metadirective_variant> &);
 
 /* Return next tree in the chain for chain_next walking of tree nodes.  */
 static inline tree
index 39c969d8f40d28e175edc9f3ce2d9e96411a5f88..cd3ba060390d1e63682392ed754ce4c88102a249 100644 (file)
@@ -449,6 +449,26 @@ genericize_omp_for_stmt (tree *stmt_p, int *walk_subtrees, void *data,
   finish_bc_block (&OMP_FOR_BODY (stmt), bc_continue, clab);
 }
 
+/* Genericize a OMP_METADIRECTIVE node *STMT_P.  */
+
+static void
+genericize_omp_metadirective_stmt (tree *stmt_p, int *walk_subtrees,
+                                  void *data, walk_tree_fn func,
+                                  walk_tree_lh lh)
+{
+  tree stmt = *stmt_p;
+
+  for (tree clause = OMP_METADIRECTIVE_CLAUSES (stmt);
+       clause != NULL_TREE;
+       clause = TREE_CHAIN (clause))
+    {
+      tree variant = TREE_VALUE (clause);
+      walk_tree_1 (&TREE_PURPOSE (variant), func, data, NULL, lh);
+      walk_tree_1 (&TREE_VALUE (variant), func, data, NULL, lh);
+    }
+
+  *walk_subtrees = 0;
+}
 
 /* Lower structured control flow tree nodes, such as loops.  The
    STMT_P, WALK_SUBTREES, and DATA arguments are as for the walk_tree_fn
@@ -497,6 +517,11 @@ c_genericize_control_stmt (tree *stmt_p, int *walk_subtrees, void *data,
       genericize_omp_for_stmt (stmt_p, walk_subtrees, data, func, lh);
       break;
 
+    case OMP_METADIRECTIVE:
+      genericize_omp_metadirective_stmt (stmt_p, walk_subtrees, data, func,
+                                        lh);
+      break;
+
     case STATEMENT_LIST:
       if (TREE_SIDE_EFFECTS (stmt))
        {
index 443d1da7189ac35ffb922d607af6a3b108aa5973..dec357e8da461b166594189a0447cfc98e537033 100644 (file)
@@ -3908,7 +3908,7 @@ static const struct c_omp_directive omp_directives[] = {
   /* { "begin", "declare", "variant", PRAGMA_OMP_BEGIN,
     C_OMP_DIR_DECLARATIVE, false }, */
   /* { "begin", "metadirective", nullptr, PRAGMA_OMP_BEGIN,
-    C_OMP_DIR_???, ??? },  */
+    C_OMP_DIR_META, false },  */
   { "cancel", nullptr, nullptr, PRAGMA_OMP_CANCEL,
     C_OMP_DIR_STANDALONE, false },
   { "cancellation", "point", nullptr, PRAGMA_OMP_CANCELLATION_POINT,
@@ -3938,7 +3938,7 @@ static const struct c_omp_directive omp_directives[] = {
   /* { "end", "declare", "variant", PRAGMA_OMP_END,
     C_OMP_DIR_DECLARATIVE, false }, */
   /* { "end", "metadirective", nullptr, PRAGMA_OMP_END,
-    C_OMP_DIR_???, ??? },  */
+    C_OMP_DIR_META, false },  */
   /* error with at(execution) is C_OMP_DIR_STANDALONE.  */
   { "error", nullptr, nullptr, PRAGMA_OMP_ERROR,
     C_OMP_DIR_UTILITY, false },
@@ -3954,8 +3954,8 @@ static const struct c_omp_directive omp_directives[] = {
     C_OMP_DIR_CONSTRUCT, true },
   { "master", nullptr, nullptr, PRAGMA_OMP_MASTER,
     C_OMP_DIR_CONSTRUCT, true },
-  /* { "metadirective", nullptr, nullptr, PRAGMA_OMP_METADIRECTIVE,
-    C_OMP_DIR_???, ??? },  */
+  { "metadirective", nullptr, nullptr, PRAGMA_OMP_METADIRECTIVE,
+    C_OMP_DIR_META, false },
   { "nothing", nullptr, nullptr, PRAGMA_OMP_NOTHING,
     C_OMP_DIR_UTILITY, false },
   /* ordered with depend clause is C_OMP_DIR_STANDALONE.  */
@@ -4038,3 +4038,9 @@ c_omp_categorize_directive (const char *first, const char *second,
     }
   return NULL;
 }
+
+tree
+c_omp_expand_metadirective (vec<struct omp_metadirective_variant> &)
+{
+  return NULL_TREE;
+}
index 6b17cb1775c5d3cb76f74962685189e4438b45a4..43c200b089fcb839f9f9d8b6aead244c5186e23f 100644 (file)
@@ -1319,6 +1319,7 @@ static const struct omp_pragma_def omp_pragmas[] = {
   { "error", PRAGMA_OMP_ERROR },
   { "end", PRAGMA_OMP_END_DECLARE_TARGET },
   { "flush", PRAGMA_OMP_FLUSH },
+  { "metadirective", PRAGMA_OMP_METADIRECTIVE },
   { "nothing", PRAGMA_OMP_NOTHING },
   { "requires", PRAGMA_OMP_REQUIRES },
   { "scope", PRAGMA_OMP_SCOPE },
index 0c5b07ab4e1095efdf93b949d37ad6e5a387f211..145260e0c20473c0680035f27d30262bc3f3f7f7 100644 (file)
@@ -61,6 +61,7 @@ enum pragma_kind {
   PRAGMA_OMP_NOTHING,
   PRAGMA_OMP_MASKED,
   PRAGMA_OMP_MASTER,
+  PRAGMA_OMP_METADIRECTIVE,
   PRAGMA_OMP_ORDERED,
   PRAGMA_OMP_PARALLEL,
   PRAGMA_OMP_REQUIRES,
index abe8886f4e66691817efa096e635a255881a10c3..f691813801feacd96f56beba538fb96511b8092c 100644 (file)
@@ -1,3 +1,16 @@
+2022-01-25  Kwok Cheung Yeung  <kcy@codesourcery.com>
+
+       * c-parser.c (c_parser_skip_to_end_of_block_or_statement): Handle
+       parentheses in statement.
+       (c_parser_omp_metadirective): New prototype.
+       (c_parser_omp_context_selector): Add extra argument.  Allow
+       non-constant expressions.
+       (c_parser_omp_context_selector_specification): Add extra argument and
+       propagate it to c_parser_omp_context_selector.
+       (analyze_metadirective_body): New.
+       (c_parser_omp_metadirective): New.
+       (c_parser_omp_construct): Handle PRAGMA_OMP_METADIRECTIVE.
+
 2021-12-22  Andrew Stubbs  <ams@codesourcery.com>
 
        * c-parser.c (c_parser_omp_requires): Don't "sorry" dynamic_allocators.
index f11281a79117b2d92b01100031256e6de263b78a..747a4193c77e836418d174fb334851cdb9de4b7d 100644 (file)
@@ -1391,6 +1391,17 @@ c_parser_skip_to_end_of_block_or_statement (c_parser *parser)
          ++nesting_depth;
          break;
 
+       case CPP_OPEN_PAREN:
+         /* Track parentheses in case the statement is a standalone 'for'
+            statement - we want to skip over the semicolons separating the
+            operands.  */
+         nesting_depth++;
+         break;
+
+       case CPP_CLOSE_PAREN:
+         nesting_depth--;
+         break;
+
        case CPP_PRAGMA:
          /* If we see a pragma, consume the whole thing at once.  We
             have some safeguards against consuming pragmas willy-nilly.
@@ -1586,6 +1597,8 @@ static bool c_parser_omp_cancellation_point (c_parser *, enum pragma_context);
 static bool c_parser_omp_target (c_parser *, enum pragma_context, bool *);
 static void c_parser_omp_end_declare_target (c_parser *);
 static bool c_parser_omp_declare (c_parser *, enum pragma_context);
+static tree c_parser_omp_metadirective (location_t, c_parser *, char *,
+                                       omp_clause_mask, tree *, bool *);
 static void c_parser_omp_requires (c_parser *);
 static bool c_parser_omp_error (c_parser *, enum pragma_context);
 static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *);
@@ -19110,6 +19123,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
   location_t for_loc;
   bool tiling = false;
   bool inscan = false;
+
   vec<tree, va_gc> *for_block = make_tree_vector ();
 
   for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
@@ -21333,7 +21347,8 @@ static const char *const omp_user_selectors[] = {
      score(score-expression)  */
 
 static tree
-c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
+c_parser_omp_context_selector (c_parser *parser, tree set, tree parms,
+                              bool metadirective_p)
 {
   tree ret = NULL_TREE;
   do
@@ -21541,10 +21556,16 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
                {
                  mark_exp_read (t);
                  t = c_fully_fold (t, false, NULL);
-                 if (!INTEGRAL_TYPE_P (TREE_TYPE (t))
-                     || !tree_fits_shwi_p (t))
+                 if (!metadirective_p
+                     && (!INTEGRAL_TYPE_P (TREE_TYPE (t))
+                         || !tree_fits_shwi_p (t)))
                    error_at (token->location, "property must be "
-                             "constant integer expression");
+                                              "constant integer expression");
+                 else if (metadirective_p
+                          && !INTEGRAL_TYPE_P (TREE_TYPE (t)))
+                   /* Allow non-constant user expressions in metadirectives.  */
+                   error_at (token->location, "property must be "
+                                              "integer expression");
                  else
                    properties = tree_cons (NULL_TREE, t, properties);
                }
@@ -21610,7 +21631,8 @@ c_parser_omp_context_selector (c_parser *parser, tree set, tree parms)
      user  */
 
 static tree
-c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
+c_parser_omp_context_selector_specification (c_parser *parser, tree parms,
+                                            bool metadirective_p = false)
 {
   tree ret = NULL_TREE;
   do
@@ -21656,7 +21678,8 @@ c_parser_omp_context_selector_specification (c_parser *parser, tree parms)
       if (!braces.require_open (parser))
        return error_mark_node;
 
-      tree selectors = c_parser_omp_context_selector (parser, set, parms);
+      tree selectors = c_parser_omp_context_selector (parser, set, parms,
+                                                     metadirective_p);
       if (selectors == error_mark_node)
        ret = error_mark_node;
       else if (ret != error_mark_node)
@@ -22860,6 +22883,368 @@ c_parser_omp_error (c_parser *parser, enum pragma_context context)
   return false;
 }
 
+/* Helper function for c_parser_omp_metadirective.  */
+
+static void
+analyze_metadirective_body (c_parser *parser,
+                           vec<c_token> &tokens,
+                           vec<tree> &labels)
+{
+  int nesting_depth = 0;
+  int bracket_depth = 0;
+  bool ignore_label = false;
+
+  /* Read in the body tokens to the tokens for each candidate directive.  */
+  while (1)
+    {
+      c_token *token = c_parser_peek_token (parser);
+      bool stop = false;
+
+      if (c_parser_next_token_is_keyword (parser, RID_CASE))
+       ignore_label = true;
+
+      switch (token->type)
+       {
+       case CPP_EOF:
+         break;
+       case CPP_NAME:
+         if (!ignore_label
+             && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+           labels.safe_push (token->value);
+         goto add;
+       case CPP_OPEN_BRACE:
+         ++nesting_depth;
+         goto add;
+       case CPP_CLOSE_BRACE:
+         if (--nesting_depth == 0)
+           stop = true;
+         goto add;
+       case CPP_OPEN_PAREN:
+         ++bracket_depth;
+         goto add;
+       case CPP_CLOSE_PAREN:
+         --bracket_depth;
+         goto add;
+       case CPP_COLON:
+         ignore_label = false;
+         goto add;
+       case CPP_SEMICOLON:
+         if (nesting_depth == 0 && bracket_depth == 0)
+           stop = true;
+         goto add;
+       default:
+       add:
+         tokens.safe_push (*token);
+         if (token->type == CPP_PRAGMA)
+           c_parser_consume_pragma (parser);
+         else if (token->type == CPP_PRAGMA_EOL)
+           c_parser_skip_to_pragma_eol (parser);
+         else
+           c_parser_consume_token (parser);
+         if (stop)
+           break;
+         continue;
+       }
+      break;
+    }
+}
+
+/* OpenMP 5.0:
+
+  # pragma omp metadirective [clause[, clause]]
+*/
+
+static tree
+c_parser_omp_metadirective (location_t loc, c_parser *parser,
+                           char *p_name, omp_clause_mask, tree *,
+                           bool *if_p)
+{
+  tree ret;
+  auto_vec<c_token> directive_tokens;
+  auto_vec<c_token> body_tokens;
+  auto_vec<tree> body_labels;
+  auto_vec<const struct c_omp_directive *> directives;
+  auto_vec<tree> ctxs;
+  vec<struct omp_metadirective_variant> candidates;
+  bool default_seen = false;
+  int directive_token_idx = 0;
+  tree standalone_body = NULL_TREE;
+
+  ret = make_node (OMP_METADIRECTIVE);
+  SET_EXPR_LOCATION (ret, loc);
+  TREE_TYPE (ret) = void_type_node;
+  OMP_METADIRECTIVE_CLAUSES (ret) = NULL_TREE;
+  strcat (p_name, " metadirective");
+
+  while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+    {
+      if (c_parser_next_token_is_not (parser, CPP_NAME)
+         && c_parser_next_token_is_not (parser, CPP_KEYWORD))
+       {
+         c_parser_error (parser, "expected %<when%> or %<default%>");
+         goto error;
+       }
+
+      location_t match_loc = c_parser_peek_token (parser)->location;
+      const char *p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+      c_parser_consume_token (parser);
+      bool default_p = strcmp (p, "default") == 0;
+      if (default_p)
+       {
+         if (default_seen)
+           {
+             c_parser_error (parser, "there can only be one default clause "
+                                     "in a metadirective");
+             goto error;
+           }
+         default_seen = true;
+       }
+      if (!(strcmp (p, "when") == 0 || default_p))
+       {
+         c_parser_error (parser, "expected %<when%> or %<default%>");
+         goto error;
+       }
+
+      matching_parens parens;
+      tree ctx = NULL_TREE;
+      bool skip = false;
+
+      if (!parens.require_open (parser))
+       goto error;
+
+      if (!default_p)
+       {
+         ctx = c_parser_omp_context_selector_specification (parser,
+                                                            NULL_TREE, true);
+         if (ctx == error_mark_node)
+           goto error;
+         ctx = omp_check_context_selector (match_loc, ctx);
+         if (ctx == error_mark_node)
+           goto error;
+
+         /* Remove the selector from further consideration if can be
+            evaluated as a non-match at this point.  */
+         skip = (omp_context_selector_matches (ctx, true) == 0);
+
+         if (c_parser_next_token_is_not (parser, CPP_COLON))
+           {
+             c_parser_error (parser, "expected colon");
+             goto error;
+           }
+         c_parser_consume_token (parser);
+       }
+
+      /* Read in the directive type and create a dummy pragma token for
+        it.  */
+      location_t loc = c_parser_peek_token (parser)->location;
+
+      p = NULL;
+      if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+       p = "nothing";
+      else if (c_parser_next_token_is_keyword (parser, RID_FOR))
+       {
+         p = "for";
+         c_parser_consume_token (parser);
+       }
+      else if (c_parser_next_token_is (parser, CPP_NAME))
+       {
+         p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+         c_parser_consume_token (parser);
+       }
+
+      if (p == NULL)
+       {
+         c_parser_error (parser, "expected directive name");
+         goto error;
+       }
+
+      const struct c_omp_directive *omp_directive
+       = c_omp_categorize_directive (p, NULL, NULL);
+
+      if (omp_directive == NULL)
+       {
+         c_parser_error (parser, "unknown directive name");
+         goto error;
+       }
+      if (omp_directive->id == PRAGMA_OMP_METADIRECTIVE)
+       {
+         c_parser_error (parser,
+                         "metadirectives cannot be used as directive "
+                         "variants");
+         goto error;
+       }
+      if (omp_directive->kind == C_OMP_DIR_DECLARATIVE)
+       {
+         sorry_at (loc, "declarative directive variants are not supported");
+         goto error;
+       }
+
+      if (!skip)
+       {
+         c_token pragma_token;
+         pragma_token.type = CPP_PRAGMA;
+         pragma_token.location = loc;
+         pragma_token.pragma_kind = (enum pragma_kind) omp_directive->id;
+
+         directives.safe_push (omp_directive);
+         directive_tokens.safe_push (pragma_token);
+         ctxs.safe_push (ctx);
+       }
+
+      /* Read in tokens for the directive clauses.  */
+      int nesting_depth = 0;
+      while (1)
+       {
+         c_token *token = c_parser_peek_token (parser);
+         switch (token->type)
+           {
+           case CPP_EOF:
+           case CPP_PRAGMA_EOL:
+             break;
+           case CPP_OPEN_PAREN:
+             ++nesting_depth;
+             goto add;
+           case CPP_CLOSE_PAREN:
+             if (nesting_depth-- == 0)
+               break;
+             goto add;
+           default:
+           add:
+             if (!skip)
+               directive_tokens.safe_push (*token);
+             c_parser_consume_token (parser);
+             continue;
+           }
+         break;
+       }
+
+      c_parser_consume_token (parser);
+
+      if (!skip)
+       {
+         c_token eol_token;
+         memset (&eol_token, 0, sizeof (eol_token));
+         eol_token.type = CPP_PRAGMA_EOL;
+         directive_tokens.safe_push (eol_token);
+       }
+    }
+  c_parser_skip_to_pragma_eol (parser);
+
+  if (!default_seen)
+    {
+      /* Add a default clause that evaluates to 'omp nothing'.  */
+      const struct c_omp_directive *omp_directive
+       = c_omp_categorize_directive ("nothing", NULL, NULL);
+
+      c_token pragma_token;
+      pragma_token.type = CPP_PRAGMA;
+      pragma_token.location = UNKNOWN_LOCATION;
+      pragma_token.pragma_kind = PRAGMA_OMP_NOTHING;
+
+      directives.safe_push (omp_directive);
+      directive_tokens.safe_push (pragma_token);
+      ctxs.safe_push (NULL_TREE);
+
+      c_token eol_token;
+      memset (&eol_token, 0, sizeof (eol_token));
+      eol_token.type = CPP_PRAGMA_EOL;
+      directive_tokens.safe_push (eol_token);
+    }
+
+  analyze_metadirective_body (parser, body_tokens, body_labels);
+
+  /* Process each candidate directive.  */
+  unsigned i;
+  tree ctx;
+
+  FOR_EACH_VEC_ELT (ctxs, i, ctx)
+    {
+      auto_vec<c_token> tokens;
+
+      /* Add the directive tokens.  */
+      do
+       tokens.safe_push (directive_tokens [directive_token_idx++]);
+      while (tokens.last ().type != CPP_PRAGMA_EOL);
+
+      /* Add the body tokens.  */
+      for (unsigned j = 0; j < body_tokens.length (); j++)
+       tokens.safe_push (body_tokens[j]);
+
+      /* Make sure nothing tries to read past the end of the tokens.  */
+      c_token eof_token;
+      memset (&eof_token, 0, sizeof (eof_token));
+      eof_token.type = CPP_EOF;
+      tokens.safe_push (eof_token);
+      tokens.safe_push (eof_token);
+
+      unsigned int old_tokens_avail = parser->tokens_avail;
+      c_token *old_tokens = parser->tokens;
+
+      parser->tokens = tokens.address ();
+      parser->tokens_avail = tokens.length ();
+
+      tree directive = c_begin_compound_stmt (true);
+
+      /* Declare all non-local labels that occur within the directive body
+        as local.  */
+      for (unsigned j = 0; j < body_labels.length (); j++)
+       {
+         tree label = declare_label (body_labels[j]);
+
+         C_DECLARED_LABEL_FLAG (label) = 1;
+         add_stmt (build_stmt (loc, DECL_EXPR, label));
+       }
+
+      c_parser_pragma (parser, pragma_compound, if_p);
+      directive = c_end_compound_stmt (loc, directive, true);
+      bool standalone_p
+       = directives[i]->kind == C_OMP_DIR_STANDALONE
+         || directives[i]->kind == C_OMP_DIR_UTILITY;
+      if (standalone_p)
+       {
+         /* Parsing standalone directives will not consume the body
+            tokens, so do that here.  */
+         if (standalone_body == NULL_TREE)
+           {
+             standalone_body = push_stmt_list ();
+             c_parser_statement (parser, if_p);
+             standalone_body = pop_stmt_list (standalone_body);
+           }
+         else
+           c_parser_skip_to_end_of_block_or_statement (parser);
+       }
+
+      tree body = standalone_p ? standalone_body : NULL_TREE;
+      tree variant = build_tree_list (ctx, build_tree_list (directive, body));
+      OMP_METADIRECTIVE_CLAUSES (ret)
+       = chainon (OMP_METADIRECTIVE_CLAUSES (ret), variant);
+
+      /* Check that all valid tokens have been consumed.  */
+      gcc_assert (parser->tokens_avail == 2);
+      gcc_assert (c_parser_next_token_is (parser, CPP_EOF));
+      gcc_assert (c_parser_peek_2nd_token (parser)->type == CPP_EOF);
+
+      parser->tokens = old_tokens;
+      parser->tokens_avail = old_tokens_avail;
+    }
+
+  /* Try to resolve the metadirective early.  */
+  candidates = omp_resolve_metadirective (ret);
+  if (!candidates.is_empty ())
+    ret = c_omp_expand_metadirective (candidates);
+
+  add_stmt (ret);
+
+  return ret;
+
+error:
+  if (parser->in_pragma)
+    c_parser_skip_to_pragma_eol (parser);
+  c_parser_skip_to_end_of_block_or_statement (parser);
+
+  return NULL_TREE;
+}
+
 /* Main entry point to parsing most OpenMP pragmas.  */
 
 static void
@@ -22933,6 +23318,11 @@ c_parser_omp_construct (c_parser *parser, bool *if_p)
       strcpy (p_name, "#pragma omp");
       stmt = c_parser_omp_master (loc, parser, p_name, mask, NULL, if_p);
       break;
+    case PRAGMA_OMP_METADIRECTIVE:
+      strcpy (p_name, "#pragma omp");
+      stmt = c_parser_omp_metadirective (loc, parser, p_name, mask, NULL,
+                                        if_p);
+      break;
     case PRAGMA_OMP_PARALLEL:
       strcpy (p_name, "#pragma omp");
       stmt = c_parser_omp_parallel (loc, parser, p_name, mask, NULL, if_p);
@@ -22973,7 +23363,6 @@ c_parser_omp_construct (c_parser *parser, bool *if_p)
     gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION);
 }
 
-
 /* OpenMP 2.5:
    # pragma omp threadprivate (variable-list) */
 
index c8aec1b18b5852e94f2e77d31d51953c07408fe1..ab77500dfd332c583572d05d591b60d42c40c894 100644 (file)
@@ -1275,7 +1275,7 @@ omp_context_name_list_prop (tree prop)
    IPA, others until vectorization.  */
 
 int
-omp_context_selector_matches (tree ctx)
+omp_context_selector_matches (tree ctx, bool)
 {
   int ret = 1;
   for (tree t1 = ctx; t1; t1 = TREE_CHAIN (t1))
@@ -2633,6 +2633,18 @@ omp_lto_input_declare_variant_alt (lto_input_block *ib, cgraph_node *node,
                                                 INSERT) = entryp;
 }
 
+/* Return a vector of dynamic replacement candidates for the metadirective
+   statement in METADIRECTIVE.  Return an empty vector if the metadirective
+   cannot be resolved.  */
+
+vec<struct omp_metadirective_variant>
+omp_resolve_metadirective (tree)
+{
+  vec<struct omp_metadirective_variant> variants = {};
+
+  return variants;
+}
+
 /* Encode an oacc launch argument.  This matches the GOMP_LAUNCH_PACK
    macro on gomp-constants.h.  We do not check for overflow.  */
 
index b27dc5e940961291bfa6ba253266a52545b6192e..eaec8f5c28152e8663b6b5b096ae079d864c4853 100644 (file)
@@ -89,6 +89,12 @@ struct omp_for_data
   tree adjn1;
 };
 
+/* A structure describing a variant in a metadirective.  */
+
+struct omp_metadirective_variant
+{
+};
+
 #define OACC_FN_ATTRIB "oacc function"
 
 extern tree omp_find_clause (tree clauses, enum omp_clause_code kind);
@@ -108,10 +114,11 @@ extern int omp_constructor_traits_to_codes (tree, enum tree_code *);
 extern tree omp_check_context_selector (location_t loc, tree ctx);
 extern void omp_mark_declare_variant (location_t loc, tree variant,
                                      tree construct);
-extern int omp_context_selector_matches (tree);
+extern int omp_context_selector_matches (tree, bool = false);
 extern int omp_context_selector_set_compare (const char *, tree, tree);
 extern tree omp_get_context_selector (tree, const char *, const char *);
 extern tree omp_resolve_declare_variant (tree);
+extern vec<struct omp_metadirective_variant> omp_resolve_metadirective (tree);
 extern tree oacc_launch_pack (unsigned code, tree device, unsigned op);
 extern tree oacc_replace_fn_attrib_attr (tree attribs, tree dims);
 extern void oacc_replace_fn_attrib (tree fn, tree dims);
index e27bc3e2b1f3f7092d8c18eb62ffde6ff1ff5841..91f8c4db1e373fbe73dcefaf982a267f2915d430 100644 (file)
@@ -1274,6 +1274,11 @@ DEFTREECODE (OMP_TARGET_ENTER_DATA, "omp_target_enter_data", tcc_statement, 1)
    Operand 0: OMP_TARGET_EXIT_DATA_CLAUSES: List of clauses.  */
 DEFTREECODE (OMP_TARGET_EXIT_DATA, "omp_target_exit_data", tcc_statement, 1)
 
+/* OpenMP - #pragma omp metadirective [clause1 ... clauseN]
+   Operand 0: OMP_METADIRECTIVE_CLAUSES: List of selectors and directive
+       variants.  */
+DEFTREECODE (OMP_METADIRECTIVE, "omp_metadirective", tcc_statement, 1)
+
 /* OMP_ATOMIC through OMP_ATOMIC_CAPTURE_NEW must be consecutive,
    or OMP_ATOMIC_SEQ_CST needs adjusting.  */
 
index cc7716f5007b7bd8f5d5af45d2007ad0a9306269..c93d1b34f9b1ca0df521bb0e8de94bf1f1204ee6 100644 (file)
@@ -1465,6 +1465,9 @@ class auto_suppress_location_wrappers
 #define OMP_TARGET_EXIT_DATA_CLAUSES(NODE)\
   TREE_OPERAND (OMP_TARGET_EXIT_DATA_CHECK (NODE), 0)
 
+#define OMP_METADIRECTIVE_CLAUSES(NODE) \
+  TREE_OPERAND (OMP_METADIRECTIVE_CHECK (NODE), 0)
+
 #define OMP_SCAN_BODY(NODE)    TREE_OPERAND (OMP_SCAN_CHECK (NODE), 0)
 #define OMP_SCAN_CLAUSES(NODE) TREE_OPERAND (OMP_SCAN_CHECK (NODE), 1)