From dc88559b0295104472a0cbf79de03b0549bd35f5 Mon Sep 17 00:00:00 2001 From: Kwok Cheung Yeung Date: Mon, 6 Dec 2021 19:15:23 +0000 Subject: [PATCH 1/7] 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-12-10 Kwok Cheung Yeung 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. --- 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/c-parser.c | 403 +++++++++++++++++++++++++++++++++++++- gcc/omp-general.c | 14 +- gcc/omp-general.h | 9 +- gcc/tree.def | 5 + gcc/tree.h | 3 + 10 files changed, 465 insertions(+), 14 deletions(-) diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index c089fda12e4..ef37051791f 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1257,7 +1257,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 { @@ -1270,6 +1271,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 &); /* 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 0d38b706f4c..4c5feddf041 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 3f84fd1b5cb..9a7a6834f1b 100644 --- a/gcc/c-family/c-omp.c +++ b/gcc/c-family/c-omp.c @@ -3133,7 +3133,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, @@ -3163,7 +3163,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 }, @@ -3179,8 +3179,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. */ @@ -3263,3 +3263,9 @@ c_omp_categorize_directive (const char *first, const char *second, } return NULL; } + +tree +c_omp_expand_metadirective (vec &) +{ + return NULL_TREE; +} diff --git a/gcc/c-family/c-pragma.c b/gcc/c-family/c-pragma.c index c4ed4205820..bd27de7f126 100644 --- a/gcc/c-family/c-pragma.c +++ b/gcc/c-family/c-pragma.c @@ -1365,6 +1365,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/c-parser.c b/gcc/c/c-parser.c index e99c84776f1..9689a221975 100644 --- a/gcc/c/c-parser.c +++ b/gcc/c/c-parser.c @@ -1390,6 +1390,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 *); @@ -19187,6 +19200,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 *for_block = make_tree_vector (); for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl)) @@ -21398,7 +21412,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 @@ -21606,10 +21621,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); } @@ -21675,7 +21696,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 @@ -21721,7 +21743,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) @@ -22930,6 +22953,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 &tokens, + vec &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 directive_tokens; + auto_vec body_tokens; + auto_vec body_labels; + auto_vec directives; + auto_vec ctxs; + vec 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 % or %"); + 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 % or %"); + 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 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 @@ -23003,6 +23388,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); @@ -23043,7 +23433,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 8fcca730471..9926cfd9d5f 100644 --- a/gcc/omp-general.c +++ b/gcc/omp-general.c @@ -1260,7 +1260,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)) @@ -2624,6 +2624,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 +omp_resolve_metadirective (tree) +{ + vec 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 a0c7c71148c..8c6009e9854 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 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 094501bd9b1..06c8140e011 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1471,6 +1471,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) -- 2.25.1