/* { "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,
/* { "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 },
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. */
}
return NULL;
}
+
+tree
+c_omp_expand_metadirective (vec<struct omp_metadirective_variant> &)
+{
+ return NULL_TREE;
+}
++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.
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 *);
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))
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
{
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);
}
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
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)
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
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);
gcc_assert (EXPR_LOCATION (stmt) != UNKNOWN_LOCATION);
}
-
/* OpenMP 2.5:
# pragma omp threadprivate (variable-list) */