[gcc/devel/omp/gcc-11] openmp: Add C support for parsing metadirectives
Kwok Yeung
kcy@gcc.gnu.org
Tue Jan 25 20:36:16 GMT 2022
https://gcc.gnu.org/g:f464df13a44b9814341659be631f051377a2ce25
commit f464df13a44b9814341659be631f051377a2ce25
Author: Kwok Cheung Yeung <kcy@codesourcery.com>
Date: Tue Jan 25 10:31:19 2022 -0800
openmp: Add C support for parsing metadirectives
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.
Diff:
---
gcc/ChangeLog.omp | 10 ++
gcc/c-family/ChangeLog.omp | 11 ++
gcc/c-family/c-common.h | 4 +-
gcc/c-family/c-gimplify.c | 25 +++
gcc/c-family/c-omp.c | 14 +-
gcc/c-family/c-pragma.c | 1 +
gcc/c-family/c-pragma.h | 1 +
gcc/c/ChangeLog.omp | 13 ++
gcc/c/c-parser.c | 403 ++++++++++++++++++++++++++++++++++++++++++++-
gcc/omp-general.c | 14 +-
gcc/omp-general.h | 9 +-
gcc/tree.def | 5 +
gcc/tree.h | 3 +
13 files changed, 499 insertions(+), 14 deletions(-)
diff --git a/gcc/ChangeLog.omp b/gcc/ChangeLog.omp
index 07f31cffc35..0615ddf515f 100644
--- a/gcc/ChangeLog.omp
+++ b/gcc/ChangeLog.omp
@@ -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:
diff --git a/gcc/c-family/ChangeLog.omp b/gcc/c-family/ChangeLog.omp
index e704d7d7261..1f0e2a83ef9 100644
--- a/gcc/c-family/ChangeLog.omp
+++ b/gcc/c-family/ChangeLog.omp
@@ -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:
diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h
index 919b8740b68..f993dab6fe4 100644
--- a/gcc/c-family/c-common.h
+++ b/gcc/c-family/c-common.h
@@ -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
diff --git a/gcc/c-family/c-gimplify.c b/gcc/c-family/c-gimplify.c
index 39c969d8f40..cd3ba060390 100644
--- a/gcc/c-family/c-gimplify.c
+++ b/gcc/c-family/c-gimplify.c
@@ -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))
{
diff --git a/gcc/c-family/c-omp.c b/gcc/c-family/c-omp.c
index 443d1da7189..dec357e8da4 100644
--- a/gcc/c-family/c-omp.c
+++ b/gcc/c-family/c-omp.c
@@ -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;
+}
diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c
index 6b17cb1775c..43c200b089f 100644
--- a/gcc/c-family/c-pragma.c
+++ b/gcc/c-family/c-pragma.c
@@ -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 },
diff --git a/gcc/c-family/c-pragma.h b/gcc/c-family/c-pragma.h
index 0c5b07ab4e1..145260e0c20 100644
--- a/gcc/c-family/c-pragma.h
+++ b/gcc/c-family/c-pragma.h
@@ -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,
diff --git a/gcc/c/ChangeLog.omp b/gcc/c/ChangeLog.omp
index abe8886f4e6..f691813801f 100644
--- a/gcc/c/ChangeLog.omp
+++ b/gcc/c/ChangeLog.omp
@@ -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.
diff --git a/gcc/c/c-parser.c b/gcc/c/c-parser.c
index f11281a7911..747a4193c77 100644
--- a/gcc/c/c-parser.c
+++ b/gcc/c/c-parser.c
@@ -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) */
diff --git a/gcc/omp-general.c b/gcc/omp-general.c
index c8aec1b18b5..ab77500dfd3 100644
--- a/gcc/omp-general.c
+++ b/gcc/omp-general.c
@@ -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. */
diff --git a/gcc/omp-general.h b/gcc/omp-general.h
index b27dc5e9409..eaec8f5c281 100644
--- a/gcc/omp-general.h
+++ b/gcc/omp-general.h
@@ -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);
diff --git a/gcc/tree.def b/gcc/tree.def
index e27bc3e2b1f..91f8c4db1e3 100644
--- a/gcc/tree.def
+++ b/gcc/tree.def
@@ -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. */
diff --git a/gcc/tree.h b/gcc/tree.h
index cc7716f5007..c93d1b34f9b 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -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)
More information about the Gcc-cvs
mailing list