From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 1729) id 95D96386DC77; Wed, 29 Jun 2022 14:43:23 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 95D96386DC77 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: Kwok Yeung To: gcc-cvs@gcc.gnu.org Subject: [gcc/devel/omp/gcc-12] openmp: Add C support for parsing metadirectives X-Act-Checkin: gcc X-Git-Author: Kwok Cheung Yeung X-Git-Refname: refs/heads/devel/omp/gcc-12 X-Git-Oldrev: 1486a6a4a8d4a0714aaa3eab00a79e870cfbc9a6 X-Git-Newrev: 1588a8976f631274f1d2612a13b9ac03d6ed1ed9 Message-Id: <20220629144323.95D96386DC77@sourceware.org> Date: Wed, 29 Jun 2022 14:43:23 +0000 (GMT) X-BeenThere: gcc-cvs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-cvs mailing list List-Unsubscribe: , List-Archive: List-Help: List-Subscribe: , X-List-Received-Date: Wed, 29 Jun 2022 14:43:23 -0000 https://gcc.gnu.org/g:1588a8976f631274f1d2612a13b9ac03d6ed1ed9 commit 1588a8976f631274f1d2612a13b9ac03d6ed1ed9 Author: Kwok Cheung Yeung 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 gcc/ * omp-general.cc (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.cc (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.cc (genericize_omp_metadirective_stmt): New. (c_genericize_control_stmt): Handle OMP_METADIRECTIVE tree nodes. * c-omp.cc (omp_directives): Classify metadirectives as C_OMP_DIR_META. (c_omp_expand_metadirective): New stub function. * c-pragma.cc (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.cc | 25 +++ gcc/c-family/c-omp.cc | 14 +- gcc/c-family/c-pragma.cc | 1 + gcc/c-family/c-pragma.h | 1 + gcc/c/ChangeLog.omp | 13 ++ gcc/c/c-parser.cc | 403 ++++++++++++++++++++++++++++++++++++++++++++- gcc/omp-general.cc | 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 1926db94dc4..b9629fcbb02 100644 --- a/gcc/ChangeLog.omp +++ b/gcc/ChangeLog.omp @@ -1,3 +1,13 @@ +2022-01-25 Kwok Cheung Yeung + + * omp-general.cc (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. + 2021-11-16 Frederik Harwath * graphite-scop-detection.cc (scop_detection::harmful_loop_in_region): diff --git a/gcc/c-family/ChangeLog.omp b/gcc/c-family/ChangeLog.omp index 4fc8c4bf354..a783f4b56e1 100644 --- a/gcc/c-family/ChangeLog.omp +++ b/gcc/c-family/ChangeLog.omp @@ -1,3 +1,14 @@ +2022-01-25 Kwok Cheung Yeung + + * c-common.h (enum c_omp_directive_kind): Add C_OMP_DIR_META. + (c_omp_expand_metadirective): New prototype. + * c-gimplify.cc (genericize_omp_metadirective_stmt): New. + (c_genericize_control_stmt): Handle OMP_METADIRECTIVE tree nodes. + * c-omp.cc (omp_directives): Classify metadirectives as C_OMP_DIR_META. + (c_omp_expand_metadirective): New stub function. + * c-pragma.cc (omp_pragmas): Add entry for metadirective. + * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_METADIRECTIVE. + 2020-08-30 Sandra Loosemore * c-omp.cc (end_test_ok_for_annotation_r): New. diff --git a/gcc/c-family/c-common.h b/gcc/c-family/c-common.h index 0bee7b41cba..85c3d5d55dd 100644 --- a/gcc/c-family/c-common.h +++ b/gcc/c-family/c-common.h @@ -1258,7 +1258,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 { @@ -1271,6 +1272,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.cc b/gcc/c-family/c-gimplify.cc index a00b0a02dcc..759d3bcc5ef 100644 --- a/gcc/c-family/c-gimplify.cc +++ b/gcc/c-family/c-gimplify.cc @@ -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.cc b/gcc/c-family/c-omp.cc index eb7867f1ca1..82c2fb6844d 100644 --- a/gcc/c-family/c-omp.cc +++ b/gcc/c-family/c-omp.cc @@ -3902,7 +3902,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, @@ -3932,7 +3932,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 }, @@ -3948,8 +3948,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. */ @@ -4032,3 +4032,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.cc b/gcc/c-family/c-pragma.cc index 4c80bdd26d6..8e4dfe5a83e 100644 --- a/gcc/c-family/c-pragma.cc +++ b/gcc/c-family/c-pragma.cc @@ -1369,6 +1369,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 54864c2ec41..0d61cead748 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 73b6bb1f78b..39f82752f9e 100644 --- a/gcc/c/ChangeLog.omp +++ b/gcc/c/ChangeLog.omp @@ -1,3 +1,16 @@ +2022-01-25 Kwok Cheung Yeung + + * c-parser.cc (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-08-19 Chung-Lin Tang * c-typeck.cc (handle_omp_array_sections_1): Robustify non-contiguous diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc index 671932e29f3..dd7338de51f 100644 --- a/gcc/c/c-parser.cc +++ b/gcc/c/c-parser.cc @@ -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 *); @@ -19239,6 +19252,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)) @@ -21463,7 +21477,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 @@ -21671,10 +21686,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); } @@ -21740,7 +21761,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 @@ -21786,7 +21808,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) @@ -22992,6 +23015,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 @@ -23065,6 +23450,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); @@ -23105,7 +23495,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.cc b/gcc/omp-general.cc index 5ee54074a86..c50a4883e03 100644 --- a/gcc/omp-general.cc +++ b/gcc/omp-general.cc @@ -1277,7 +1277,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)) @@ -2641,6 +2641,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 5bfa930b5bd..01701534205 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 62650b6934b..d722064f804 100644 --- a/gcc/tree.def +++ b/gcc/tree.def @@ -1280,6 +1280,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 4377fa88464..745f1ddeb3d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -1482,6 +1482,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)