@@ -1,3 +1,12 @@
+2023-06-13 Sandra Loosemore <sandra@codesourcery.com>
+
+ * omp-api.h: New.
+ * omp-general.cc (omp_runtime_api_procname): New.
+ (omp_runtime_api_call): Moved here from omp-low.cc, and make
+ non-static.
+ * omp-general.h: Include omp-api.h.
+ * omp-low.cc (omp_runtime_api_call): Delete this copy.
+
2023-06-13 Sandra Loosemore <sandra@codesourcery.com>
Frederik Harwath <frederik@codesourcery.com>
@@ -1,3 +1,22 @@
+2023-06-13 Sandra Loosemore <sandra@codesourcery.com>
+
+ * c-parser.cc (struct c_parser): Add omp_for_parse_state field.
+ (struct omp_for_parse_data): New.
+ (check_omp_intervening_code): New.
+ (c_parser_compound_statement_nostart): Recognize intervening code
+ and nested loops in OpenMP loop constructs, and handle each
+ appropriately.
+ (c_parser_while_statement): Error on loop in intervening code.
+ (c_parser_do_statement): Likewise.
+ (c_parser_for_statement): Likewise.
+ (c_parser_postfix_expression_after_primary): Error on calls to
+ the OpenMP runtime in intervening code.
+ (c_parser_pragma): Error on OpenMP pragmas in intervening code.
+ (c_parser_see_omp_loop_nest): New.
+ (c_parser_omp_loop_nest): New.
+ (c_parser_omp_for_loop): Rewrite to use recursive descent, calling
+ c_parser_omp_loop_nest to do the heavy lifting.
+
2023-06-12 Tobias Burnus <tobias@codesourcery.com>
Backported from mainline:
@@ -249,6 +249,10 @@ struct GTY(()) c_parser {
/* Location of the last consumed token. */
location_t last_token_location;
+
+ /* Holds state for parsing collapsed OMP_FOR loops. Managed by
+ c_parser_omp_for_loop. */
+ struct omp_for_parse_data * GTY((skip)) omp_for_parse_state;
};
/* Return a pointer to the Nth token in PARSERs tokens_buf. */
@@ -1539,6 +1543,24 @@ struct oacc_routine_data {
/* Used for parsing objc foreach statements. */
static tree objc_foreach_break_label, objc_foreach_continue_label;
+/* Used for parsing OMP for loops. See c_parser_omp_for_loop. */
+struct omp_for_parse_data {
+ tree declv, condv, incrv, initv;
+ tree pre_body;
+ tree bindings;
+ int count;
+ int depth;
+ location_t for_loc;
+ bool want_nested_loop : 1;
+ bool ordered : 1;
+ bool in_intervening_code : 1;
+ bool perfect_nesting_fail : 1;
+ bool fail : 1;
+ bool inscan : 1;
+ enum tree_code code;
+ tree clauses;
+};
+
static bool c_parser_nth_token_starts_std_attributes (c_parser *,
unsigned int);
static tree c_parser_std_attribute_specifier_sequence (c_parser *);
@@ -1630,6 +1652,8 @@ static void c_parser_omp_threadprivate (c_parser *);
static void c_parser_omp_barrier (c_parser *);
static void c_parser_omp_depobj (c_parser *);
static void c_parser_omp_flush (c_parser *);
+static bool c_parser_see_omp_loop_nest (c_parser *, enum tree_code, bool);
+static tree c_parser_omp_loop_nest (c_parser *, bool *);
static tree c_parser_omp_for_loop (location_t, c_parser *, enum tree_code,
tree, tree *, bool *);
static void c_parser_omp_taskwait (c_parser *);
@@ -6127,6 +6151,66 @@ c_parser_compound_statement (c_parser *parser, location_t *endlocp)
return c_end_compound_stmt (brace_loc, stmt, true);
}
+/* Diagnose errors related to imperfectly nested loops in an OMP
+ loop construct. This function is called when such code is seen.
+ Only issue one such diagnostic no matter how much invalid
+ intervening code there is in the loop.
+ FIXME: maybe the location associated with the diagnostic should
+ be the current parser token instead of the location of the outer loop
+ nest. */
+
+static void
+check_omp_intervening_code (c_parser *parser)
+{
+ struct omp_for_parse_data *omp_for_parse_state = parser->omp_for_parse_state;
+ gcc_assert (omp_for_parse_state);
+
+ /* Only diagnose errors related to perfect nesting once. */
+ if (!omp_for_parse_state->perfect_nesting_fail)
+ {
+
+ /* OpenACC does not (yet) permit intervening code, in
+ addition to situations forbidden by the OpenMP spec. */
+ if (omp_for_parse_state->code == OACC_LOOP)
+ {
+ error_at (omp_for_parse_state->for_loc,
+ "inner loops must be perfectly nested in "
+ "%<#pragma acc loop%>");
+ omp_for_parse_state->perfect_nesting_fail = true;
+ }
+ else if (omp_for_parse_state->ordered)
+ {
+ error_at (omp_for_parse_state->for_loc,
+ "inner loops must be perfectly nested with "
+ "%<ordered%> clause");
+ omp_for_parse_state->perfect_nesting_fail = true;
+ }
+ else if (omp_for_parse_state->inscan)
+ {
+ error_at (omp_for_parse_state->for_loc,
+ "inner loops must be perfectly nested with "
+ "%<reduction%> %<inscan%> clause");
+ omp_for_parse_state->perfect_nesting_fail = true;
+ }
+ else
+ {
+ tree c = omp_find_clause (omp_for_parse_state->clauses,
+ OMP_CLAUSE_TILE);
+ if (c &&
+ ((int) tree_to_uhwi (OMP_CLAUSE_TRANSFORM_LEVEL (c))
+ <= omp_for_parse_state->depth))
+ {
+ error_at (omp_for_parse_state->for_loc,
+ "inner loops must be perfectly nested "
+ "with %<tile%> directive");
+ omp_for_parse_state->perfect_nesting_fail = true;
+ }
+ }
+ if (omp_for_parse_state->perfect_nesting_fail)
+ omp_for_parse_state->fail = true;
+ }
+}
+
/* Parse a compound statement except for the opening brace. This is
used for parsing both compound statements and statement expressions
(which follow different paths to handling the opening). */
@@ -6138,6 +6222,9 @@ c_parser_compound_statement_nostart (c_parser *parser)
bool last_label = false;
bool save_valid_for_pragma = valid_location_for_stdc_pragma_p ();
location_t label_loc = UNKNOWN_LOCATION; /* Quiet warning. */
+ struct omp_for_parse_data *omp_for_parse_state
+ = parser->omp_for_parse_state;
+
if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
{
location_t endloc = c_parser_peek_token (parser)->location;
@@ -6192,6 +6279,10 @@ c_parser_compound_statement_nostart (c_parser *parser)
{
location_t loc = c_parser_peek_token (parser)->location;
loc = expansion_point_location_if_in_system_header (loc);
+
+ bool want_nested_loop = (omp_for_parse_state ?
+ omp_for_parse_state->want_nested_loop : false);
+
/* Standard attributes may start a label, statement or declaration. */
bool have_std_attrs
= c_parser_nth_token_starts_std_attributes (parser, 1);
@@ -6210,6 +6301,8 @@ c_parser_compound_statement_nostart (c_parser *parser)
last_label = true;
last_stmt = false;
mark_valid_location_for_stdc_pragma (false);
+ if (omp_for_parse_state)
+ check_omp_intervening_code (parser);
c_parser_label (parser, std_attrs);
}
else if (c_parser_next_tokens_start_declaration (parser)
@@ -6220,14 +6313,21 @@ c_parser_compound_statement_nostart (c_parser *parser)
pedwarn_c11 (c_parser_peek_token (parser)->location, OPT_Wpedantic,
"a label can only be part of a statement and "
"a declaration is not a statement");
-
+ /* It's unlikely we'll see a nested loop in a declaration in
+ intervening code in an OMP loop, but disallow it anyway. */
+ if (omp_for_parse_state)
+ {
+ check_omp_intervening_code (parser);
+ omp_for_parse_state->want_nested_loop = false;
+ }
mark_valid_location_for_stdc_pragma (false);
bool fallthru_attr_p = false;
c_parser_declaration_or_fndef (parser, true, !have_std_attrs,
true, true, true, NULL,
NULL, have_std_attrs, std_attrs,
NULL, &fallthru_attr_p);
-
+ if (omp_for_parse_state)
+ omp_for_parse_state->want_nested_loop = want_nested_loop;
if (last_stmt && !fallthru_attr_p)
pedwarn_c90 (loc, OPT_Wdeclaration_after_statement,
"ISO C90 forbids mixed declarations and code");
@@ -6255,9 +6355,18 @@ c_parser_compound_statement_nostart (c_parser *parser)
ext = disable_extension_diagnostics ();
c_parser_consume_token (parser);
last_label = false;
+ /* It's unlikely we'll see a nested loop in a declaration in
+ intervening code in an OMP loop, but disallow it anyway. */
+ if (omp_for_parse_state)
+ {
+ check_omp_intervening_code (parser);
+ omp_for_parse_state->want_nested_loop = false;
+ }
mark_valid_location_for_stdc_pragma (false);
c_parser_declaration_or_fndef (parser, true, true, true, true,
true);
+ if (omp_for_parse_state)
+ omp_for_parse_state->want_nested_loop = want_nested_loop;
/* Following the old parser, __extension__ does not
disable this diagnostic. */
restore_extension_diagnostics (ext);
@@ -6269,6 +6378,16 @@ c_parser_compound_statement_nostart (c_parser *parser)
else
goto statement;
}
+ else if (want_nested_loop
+ && c_parser_see_omp_loop_nest (parser,
+ omp_for_parse_state->code,
+ false))
+ {
+ /* Special treatment for collapsed loop nests. */
+ omp_for_parse_state->depth++;
+ add_stmt (c_parser_omp_loop_nest (parser, NULL));
+ omp_for_parse_state->depth--;
+ }
else if (c_parser_next_token_is (parser, CPP_PRAGMA))
{
if (have_std_attrs)
@@ -6311,7 +6430,20 @@ c_parser_compound_statement_nostart (c_parser *parser)
last_label = false;
last_stmt = true;
mark_valid_location_for_stdc_pragma (false);
- c_parser_statement_after_labels (parser, NULL);
+ if (omp_for_parse_state
+ && !c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ /* Nested loops can only appear directly or nested in
+ compound statements. We have neither, so set the bit
+ to treat everything inside the subsequent statement
+ as intervening code instead. */
+ omp_for_parse_state->want_nested_loop = false;
+ check_omp_intervening_code (parser);
+ c_parser_statement_after_labels (parser, NULL);
+ omp_for_parse_state->want_nested_loop = want_nested_loop;
+ }
+ else
+ c_parser_statement_after_labels (parser, NULL);
}
parser->error = false;
@@ -7153,6 +7285,14 @@ c_parser_while_statement (c_parser *parser, bool ivdep, unsigned short unroll,
gcc_assert (c_parser_next_token_is_keyword (parser, RID_WHILE));
token_indent_info while_tinfo
= get_token_indent_info (c_parser_peek_token (parser));
+
+ if (parser->omp_for_parse_state)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "loop not permitted in intervening code in OpenMP loop body");
+ parser->omp_for_parse_state->fail = true;
+ }
+
c_parser_consume_token (parser);
block = c_begin_compound_stmt (flag_isoc99);
loc = c_parser_peek_token (parser)->location;
@@ -7204,6 +7344,14 @@ c_parser_do_statement (c_parser *parser, bool ivdep, unsigned short unroll)
unsigned char save_in_statement;
location_t loc;
gcc_assert (c_parser_next_token_is_keyword (parser, RID_DO));
+
+ if (parser->omp_for_parse_state)
+ {
+ error_at (c_parser_peek_token (parser)->location,
+ "loop not permitted in intervening code in OpenMP loop body");
+ parser->omp_for_parse_state->fail = true;
+ }
+
c_parser_consume_token (parser);
if (c_parser_next_token_is (parser, CPP_SEMICOLON))
warning_at (c_parser_peek_token (parser)->location,
@@ -7310,6 +7458,14 @@ c_parser_for_statement (c_parser *parser, bool ivdep, unsigned short unroll,
gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
token_indent_info for_tinfo
= get_token_indent_info (c_parser_peek_token (parser));
+
+ if (parser->omp_for_parse_state)
+ {
+ error_at (for_loc,
+ "loop not permitted in intervening code in OpenMP loop body");
+ parser->omp_for_parse_state->fail = true;
+ }
+
c_parser_consume_token (parser);
/* Open a compound statement in Objective-C as well, just in case this is
as foreach expression. */
@@ -11249,6 +11405,14 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
&& fndecl_built_in_p (expr.value, BUILT_IN_NORMAL)
&& vec_safe_length (exprlist) == 1)
warn_for_abs (expr_loc, expr.value, (*exprlist)[0]);
+ if (parser->omp_for_parse_state
+ && parser->omp_for_parse_state->in_intervening_code
+ && omp_runtime_api_call (expr.value))
+ {
+ error_at (expr_loc, "calls to the OpenMP runtime API are "
+ "not permitted in intervening code");
+ parser->omp_for_parse_state->fail = true;
+ }
}
start = expr.get_start ();
@@ -13083,6 +13247,19 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p)
input_location = c_parser_peek_token (parser)->location;
id = c_parser_peek_token (parser)->pragma_kind;
gcc_assert (id != PRAGMA_NONE);
+ if (parser->omp_for_parse_state
+ && parser->omp_for_parse_state->in_intervening_code
+ && id >= PRAGMA_OMP__START_
+ && id <= PRAGMA_OMP__LAST_
+ && id != PRAGMA_OMP_UNROLL
+ && id != PRAGMA_OMP_TILE)
+ {
+ error_at (input_location,
+ "intervening code must not contain OpenMP directives");
+ parser->omp_for_parse_state->fail = true;
+ c_parser_skip_until_found (parser, CPP_PRAGMA_EOL, NULL);
+ return false;
+ }
switch (id)
{
@@ -20565,6 +20742,337 @@ c_parser_omp_scan_loop_body (c_parser *parser, bool open_brace_parsed)
static int c_parser_omp_nested_loop_transform_clauses (c_parser *, tree &, int,
int, const char *);
+/* Check that the next token starts a loop nest. Return true if yes,
+ otherwise diagnose an error if ERROR_P is true, and return false. */
+static bool
+c_parser_see_omp_loop_nest (c_parser *parser, enum tree_code code,
+ bool error_p)
+{
+ if (code == OACC_LOOP)
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_FOR))
+ return true;
+ if (error_p)
+ c_parser_error (parser, "for statement expected");
+ }
+ else
+ {
+ if (c_parser_next_token_is_keyword (parser, RID_FOR)
+ || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_UNROLL
+ || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_TILE)
+ return true;
+ if (error_p)
+ c_parser_error (parser, "loop nest expected");
+ }
+ return false;
+}
+
+/* This function parses a single level of a loop nest, invoking itself
+ recursively if necessary.
+
+ loop-nest :: for (...) loop-body
+ | loop-transformation-construct
+ | generated-canonical-loop
+ loop-body :: loop-nest
+ | { [intervening-code] loop-body [intervening-code] }
+ | final-loop-body
+ intervening-code :: structured-block-sequence
+ final-loop-body :: structured-block
+
+ For a collapsed loop nest, only a single OMP_FOR is built, pulling out
+ all the iterator information from the inner loops into the
+ parser->omp_for_parse_state structure.
+
+ The iterator decl, init, cond, and incr are stored in vectors.
+
+ Initialization code for iterator variables is collected into
+ parser->omp_for_parse_state->pre_body and ends up inserted directly
+ into the OMP_FOR structure. */
+
+static tree
+c_parser_omp_loop_nest (c_parser *parser, bool *if_p)
+{
+ tree decl, cond, incr, init;
+ tree body = NULL_TREE;
+ matching_parens parens;
+ bool moreloops;
+ unsigned char save_in_statement;
+ tree loop_scope;
+ location_t loc = c_parser_peek_token (parser)->location;
+ struct omp_for_parse_data *omp_for_parse_state
+ = parser->omp_for_parse_state;
+ gcc_assert (omp_for_parse_state);
+ int depth = omp_for_parse_state->depth;
+
+ /* Handle loop transformations first. Note that when we get here
+ omp_for_parse_state->depth has already been incremented to indicate
+ the depth of the *next* loop, not the level of the loop body the
+ transformation directive appears in. */
+ if (c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_UNROLL
+ || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_TILE)
+ {
+ int count = omp_for_parse_state->count;
+ int more = c_parser_omp_nested_loop_transform_clauses (
+ parser, omp_for_parse_state->clauses,
+ depth, count - depth, "loop collapse");
+ if (depth + more > count)
+ {
+ count = depth + more;
+ omp_for_parse_state->count = count;
+ omp_for_parse_state->declv
+ = grow_tree_vec (omp_for_parse_state->declv, count);
+ omp_for_parse_state->initv
+ = grow_tree_vec (omp_for_parse_state->initv, count);
+ omp_for_parse_state->condv
+ = grow_tree_vec (omp_for_parse_state->condv, count);
+ omp_for_parse_state->incrv
+ = grow_tree_vec (omp_for_parse_state->incrv, count);
+ }
+ if (c_parser_see_omp_loop_nest (parser, omp_for_parse_state->code,
+ true))
+ return c_parser_omp_loop_nest (parser, if_p);
+ else
+ {
+ /* FIXME: Better error recovery here? */
+ omp_for_parse_state->fail = true;
+ return NULL_TREE;
+ }
+ }
+
+ /* We have already matched the FOR token but not consumed it yet. */
+ gcc_assert (c_parser_next_token_is_keyword (parser, RID_FOR));
+ c_parser_consume_token (parser);
+
+ /* Forbid break/continue in the loop initializer, condition, and
+ increment expressions. */
+ save_in_statement = in_statement;
+ in_statement = IN_OMP_BLOCK;
+
+ /* We are not in intervening code now. */
+ omp_for_parse_state->in_intervening_code = false;
+
+ if (!parens.require_open (parser))
+ {
+ omp_for_parse_state->fail = true;
+ return NULL_TREE;
+ }
+
+ /* An implicit scope block surrounds each level of FOR loop, for
+ declarations of iteration variables at this loop depth. */
+ loop_scope = c_begin_compound_stmt (true);
+
+ /* Parse the initialization declaration or expression. */
+ if (c_parser_next_tokens_start_declaration (parser))
+ {
+ /* This is a declaration, which must be added to the pre_body code. */
+ tree this_pre_body = push_stmt_list ();
+ c_in_omp_for = true;
+ c_parser_declaration_or_fndef (parser, true, true, true, true, true);
+ c_in_omp_for = false;
+ this_pre_body = pop_stmt_list (this_pre_body);
+ append_to_statement_list_force (this_pre_body,
+ &(omp_for_parse_state->pre_body));
+ decl = check_for_loop_decls (omp_for_parse_state->for_loc, flag_isoc99);
+ if (decl == NULL)
+ goto error_init;
+ if (DECL_INITIAL (decl) == error_mark_node)
+ decl = error_mark_node;
+ init = decl;
+ }
+ else if (c_parser_next_token_is (parser, CPP_NAME)
+ && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
+ {
+ struct c_expr decl_exp;
+ struct c_expr init_exp;
+ location_t init_loc;
+
+ decl_exp = c_parser_postfix_expression (parser);
+ decl = decl_exp.value;
+
+ c_parser_require (parser, CPP_EQ, "expected %<=%>");
+
+ init_loc = c_parser_peek_token (parser)->location;
+ init_exp = c_parser_expr_no_commas (parser, NULL);
+ init_exp = default_function_array_read_conversion (init_loc,
+ init_exp);
+ c_in_omp_for = true;
+ init = build_modify_expr (init_loc, decl, decl_exp.original_type,
+ NOP_EXPR, init_loc, init_exp.value,
+ init_exp.original_type);
+ c_in_omp_for = false;
+ init = c_process_expr_stmt (init_loc, init);
+
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+ }
+ else
+ {
+ error_init:
+ c_parser_error (parser,
+ "expected iteration declaration or initialization");
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
+ "expected %<)%>");
+ omp_for_parse_state->fail = true;
+ goto parse_next;
+ }
+
+ /* Parse the loop condition. */
+ cond = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
+ {
+ location_t cond_loc = c_parser_peek_token (parser)->location;
+ c_in_omp_for = true;
+ struct c_expr cond_expr
+ = c_parser_binary_expression (parser, NULL, NULL_TREE);
+ c_in_omp_for = false;
+
+ cond = cond_expr.value;
+ cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
+ switch (cond_expr.original_code)
+ {
+ case GT_EXPR:
+ case GE_EXPR:
+ case LT_EXPR:
+ case LE_EXPR:
+ break;
+ case NE_EXPR:
+ if (omp_for_parse_state->code != OACC_LOOP)
+ break;
+ /* FALLTHRU. */
+ default:
+ /* Can't be cond = error_mark_node, because we want to preserve
+ the location until c_finish_omp_for. */
+ cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
+ break;
+ }
+ protected_set_expr_location (cond, cond_loc);
+ }
+ c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
+
+ /* Parse the increment expression. */
+ incr = NULL_TREE;
+ if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
+ {
+ location_t incr_loc = c_parser_peek_token (parser)->location;
+
+ incr = c_process_expr_stmt (incr_loc,
+ c_parser_expression (parser).value);
+ }
+ parens.skip_until_found_close (parser);
+
+ if (decl == NULL || decl == error_mark_node || init == error_mark_node)
+ omp_for_parse_state->fail = true;
+ else
+ {
+ TREE_VEC_ELT (omp_for_parse_state->declv, depth) = decl;
+ TREE_VEC_ELT (omp_for_parse_state->initv, depth) = init;
+ TREE_VEC_ELT (omp_for_parse_state->condv, depth) = cond;
+ TREE_VEC_ELT (omp_for_parse_state->incrv, depth) = incr;
+ }
+
+parse_next:
+ moreloops = depth < omp_for_parse_state->count - 1;
+ omp_for_parse_state->want_nested_loop = moreloops;
+ if (moreloops
+ && (c_parser_next_token_is_keyword (parser, RID_FOR)
+ || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_UNROLL
+ || c_parser_peek_token (parser)->pragma_kind == PRAGMA_OMP_TILE))
+ {
+ omp_for_parse_state->depth++;
+ body = c_parser_omp_loop_nest (parser, if_p);
+ omp_for_parse_state->depth--;
+ }
+ else if (moreloops && c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ {
+ /* This is the open brace in the loop-body grammar production. Rather
+ than trying to special-case braces, just parse it as a compound
+ statement and handle the nested loop-body case there. Note that
+ when we see a further open brace inside the compound statement
+ loop-body, we don't know whether it is the start of intervening
+ code that is a compound statement, or a level of braces
+ surrounding a nested loop-body. Use the WANT_NESTED_LOOP state
+ bit to ensure we have only one nested loop at each level. */
+ omp_for_parse_state->in_intervening_code = true;
+ body = c_parser_compound_statement (parser, NULL);
+ omp_for_parse_state->in_intervening_code = false;
+ if (omp_for_parse_state->want_nested_loop)
+ {
+ /* We have already parsed the whole loop body and not found a
+ nested loop. */
+ error_at (omp_for_parse_state->for_loc,
+ "not enough nested loops");
+ omp_for_parse_state->fail = true;
+ }
+ if_p = NULL;
+ }
+ else
+ {
+ /* This is the final-loop-body case in the grammar: we have
+ something that is not a FOR and not an open brace. */
+ if (moreloops)
+ {
+ /* If we were expecting a nested loop, give an error and mark
+ that parsing has failed, and try to recover by parsing the
+ body as regular code without further collapsing. */
+ error_at (omp_for_parse_state->for_loc,
+ "not enough nested loops");
+ omp_for_parse_state->fail = true;
+ }
+ in_statement = IN_OMP_FOR;
+ parser->omp_for_parse_state = NULL;
+ body = push_stmt_list ();
+ if (omp_for_parse_state->inscan)
+ c_parser_omp_scan_loop_body (parser, false);
+ else
+ add_stmt (c_parser_c99_block_statement (parser, if_p));
+ body = pop_stmt_list (body);
+ parser->omp_for_parse_state = omp_for_parse_state;
+ }
+ in_statement = save_in_statement;
+ omp_for_parse_state->want_nested_loop = false;
+ omp_for_parse_state->in_intervening_code = true;
+
+ /* Pop and return the implicit scope surrounding this level of loop.
+ If the iteration variable at this depth was bound in the for loop,
+ pull out and save the binding. Later in c_parser_omp_for_loop,
+ these bindings will be moved to the scope surrounding the entire
+ OMP_FOR. That keeps the gimplifier happy later on, and meanwhile
+ we have already resolved all references to the iteration variable
+ in its true scope. */
+ add_stmt (body);
+ body = c_end_compound_stmt (loc, loop_scope, true);
+ if (decl && TREE_CODE (body) == BIND_EXPR)
+ {
+ tree t = BIND_EXPR_VARS (body);
+ tree prev = NULL_TREE, next = NULL_TREE;
+ while (t)
+ {
+ next = DECL_CHAIN (t);
+ if (t == decl)
+ {
+ if (prev)
+ DECL_CHAIN (prev) = next;
+ else
+ {
+ BIND_EXPR_VARS (body) = next;
+ BLOCK_VARS (BIND_EXPR_BLOCK (body)) = next;
+ }
+ DECL_CHAIN (t) = omp_for_parse_state->bindings;
+ omp_for_parse_state->bindings = t;
+ break;
+ }
+ else
+ {
+ prev = t;
+ t = next;
+ }
+ }
+ if (BIND_EXPR_VARS (body) == NULL_TREE)
+ body = BIND_EXPR_BODY (body);
+ }
+
+ return body;
+}
+
/* Parse the restricted form of loop statements allowed by OpenACC and OpenMP.
The real trick here is to determine the loop control variable early
so that we can push a new decl if necessary to make it private.
@@ -20575,18 +21083,14 @@ static tree
c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
tree clauses, tree *cclauses, bool *if_p)
{
- tree decl, cond, incr, body, init, stmt, cl;
- unsigned char save_in_statement;
- tree declv, condv, incrv, initv, ret = NULL_TREE;
- tree pre_body = NULL_TREE, this_pre_body;
+ tree body, stmt, cl;
+ tree ret = NULL_TREE;
tree ordered_cl = NULL_TREE;
- bool fail = false, open_brace_parsed = false;
- int i, collapse = 1, ordered = 0, count, nbraces = 0;
- location_t for_loc;
+ int i, collapse = 1, ordered = 0, count;
bool oacc_tiling = false;
bool inscan = false;
-
- vec<tree, va_gc> *for_block = make_tree_vector ();
+ struct omp_for_parse_data data;
+ struct omp_for_parse_data *save_data = parser->omp_for_parse_state;
for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
@@ -20638,266 +21142,53 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
count = ordered ? ordered : collapse;
count = MAX (count, omp_tile_depth);
- declv = make_tree_vec (count);
- initv = make_tree_vec (count);
- condv = make_tree_vec (count);
- incrv = make_tree_vec (count);
-
- if (!c_parser_next_token_is_keyword (parser, RID_FOR))
- {
- c_parser_error (parser, "for statement expected");
- return NULL;
- }
- for_loc = c_parser_peek_token (parser)->location;
- c_parser_consume_token (parser);
-
- /* Forbid break/continue in the loop initializer, condition, and
- increment expressions. */
- save_in_statement = in_statement;
- in_statement = IN_OMP_BLOCK;
-
- for (i = 0; i < count; i++)
- {
- int bracecount = 0;
-
- matching_parens parens;
- if (!parens.require_open (parser))
- goto pop_scopes;
-
- /* Parse the initialization declaration or expression. */
- if (c_parser_next_tokens_start_declaration (parser))
- {
- if (i > 0)
- vec_safe_push (for_block, c_begin_compound_stmt (true));
- this_pre_body = push_stmt_list ();
- c_in_omp_for = true;
- c_parser_declaration_or_fndef (parser, true, true, true, true, true);
- c_in_omp_for = false;
- if (this_pre_body)
- {
- this_pre_body = pop_stmt_list (this_pre_body);
- if (pre_body)
- {
- tree t = pre_body;
- pre_body = push_stmt_list ();
- add_stmt (t);
- add_stmt (this_pre_body);
- pre_body = pop_stmt_list (pre_body);
- }
- else
- pre_body = this_pre_body;
- }
- decl = check_for_loop_decls (for_loc, flag_isoc99);
- if (decl == NULL)
- goto error_init;
- if (DECL_INITIAL (decl) == error_mark_node)
- decl = error_mark_node;
- init = decl;
- }
- else if (c_parser_next_token_is (parser, CPP_NAME)
- && c_parser_peek_2nd_token (parser)->type == CPP_EQ)
- {
- struct c_expr decl_exp;
- struct c_expr init_exp;
- location_t init_loc;
-
- decl_exp = c_parser_postfix_expression (parser);
- decl = decl_exp.value;
-
- c_parser_require (parser, CPP_EQ, "expected %<=%>");
-
- init_loc = c_parser_peek_token (parser)->location;
- init_exp = c_parser_expr_no_commas (parser, NULL);
- init_exp = default_function_array_read_conversion (init_loc,
- init_exp);
- c_in_omp_for = true;
- init = build_modify_expr (init_loc, decl, decl_exp.original_type,
- NOP_EXPR, init_loc, init_exp.value,
- init_exp.original_type);
- c_in_omp_for = false;
- init = c_process_expr_stmt (init_loc, init);
-
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
- }
- else
- {
- error_init:
- c_parser_error (parser,
- "expected iteration declaration or initialization");
- c_parser_skip_until_found (parser, CPP_CLOSE_PAREN,
- "expected %<)%>");
- fail = true;
- goto parse_next;
- }
-
- /* Parse the loop condition. */
- cond = NULL_TREE;
- if (c_parser_next_token_is_not (parser, CPP_SEMICOLON))
- {
- location_t cond_loc = c_parser_peek_token (parser)->location;
- c_in_omp_for = true;
- struct c_expr cond_expr
- = c_parser_binary_expression (parser, NULL, NULL_TREE);
- c_in_omp_for = false;
-
- cond = cond_expr.value;
- cond = c_objc_common_truthvalue_conversion (cond_loc, cond);
- switch (cond_expr.original_code)
- {
- case GT_EXPR:
- case GE_EXPR:
- case LT_EXPR:
- case LE_EXPR:
- break;
- case NE_EXPR:
- if (code != OACC_LOOP)
- break;
- /* FALLTHRU. */
- default:
- /* Can't be cond = error_mark_node, because we want to preserve
- the location until c_finish_omp_for. */
- cond = build1 (NOP_EXPR, boolean_type_node, error_mark_node);
- break;
- }
- protected_set_expr_location (cond, cond_loc);
- }
- c_parser_skip_until_found (parser, CPP_SEMICOLON, "expected %<;%>");
-
- /* Parse the increment expression. */
- incr = NULL_TREE;
- if (c_parser_next_token_is_not (parser, CPP_CLOSE_PAREN))
- {
- location_t incr_loc = c_parser_peek_token (parser)->location;
-
- incr = c_process_expr_stmt (incr_loc,
- c_parser_expression (parser).value);
- }
- parens.skip_until_found_close (parser);
-
- if (decl == NULL || decl == error_mark_node || init == error_mark_node)
- fail = true;
- else
- {
- TREE_VEC_ELT (declv, i) = decl;
- TREE_VEC_ELT (initv, i) = init;
- TREE_VEC_ELT (condv, i) = cond;
- TREE_VEC_ELT (incrv, i) = incr;
- }
-
- parse_next:
- if (i == count - 1)
- break;
-
- /* FIXME: OpenMP 3.0 draft isn't very clear on what exactly is allowed
- in between the collapsed for loops to be still considered perfectly
- nested. Hopefully the final version clarifies this.
- For now handle (multiple) {'s and empty statements. */
- do
- {
- if (c_parser_next_token_is_keyword (parser, RID_FOR))
- {
- c_parser_consume_token (parser);
- break;
- }
- else if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
- {
- c_parser_consume_token (parser);
- bracecount++;
- }
- else if (bracecount
- && c_parser_next_token_is (parser, CPP_SEMICOLON))
- c_parser_consume_token (parser);
- else if (c_parser_peek_token (parser)->pragma_kind
- == PRAGMA_OMP_UNROLL
- || c_parser_peek_token (parser)->pragma_kind
- == PRAGMA_OMP_TILE)
- {
- int depth = c_parser_omp_nested_loop_transform_clauses (
- parser, clauses, i + 1, count - i - 1, "loop collapse");
- if (i + 1 + depth > count)
- {
- count = i + 1 + depth;
- declv = grow_tree_vec (declv, count);
- initv = grow_tree_vec (initv, count);
- condv = grow_tree_vec (condv, count);
- incrv = grow_tree_vec (incrv, count);
- }
- }
- else
- {
- c_parser_error (parser, "not enough perfectly nested loops");
- if (bracecount)
- {
- open_brace_parsed = true;
- bracecount--;
- }
- fail = true;
- count = 0;
- break;
- }
- }
- while (1);
-
- nbraces += bracecount;
- }
-
- if (nbraces)
- if_p = NULL;
-
- in_statement = IN_OMP_FOR;
- body = push_stmt_list ();
-
- if (inscan)
- c_parser_omp_scan_loop_body (parser, open_brace_parsed);
- else if (open_brace_parsed)
- {
- location_t here = c_parser_peek_token (parser)->location;
- stmt = c_begin_compound_stmt (true);
- c_parser_compound_statement_nostart (parser);
- add_stmt (c_end_compound_stmt (here, stmt, true));
- }
- else
- add_stmt (c_parser_c99_block_statement (parser, if_p));
-
- body = pop_stmt_list (body);
- in_statement = save_in_statement;
+ if (!c_parser_see_omp_loop_nest (parser, code, true))
+ return NULL;
- while (nbraces)
- {
- if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
- {
- c_parser_consume_token (parser);
- nbraces--;
- }
- else if (c_parser_next_token_is (parser, CPP_SEMICOLON))
- c_parser_consume_token (parser);
- else
- {
- c_parser_error (parser, "collapsed loops not perfectly nested");
- while (nbraces)
- {
- location_t here = c_parser_peek_token (parser)->location;
- stmt = c_begin_compound_stmt (true);
- add_stmt (body);
- c_parser_compound_statement_nostart (parser);
- body = c_end_compound_stmt (here, stmt, true);
- nbraces--;
- }
- goto pop_scopes;
- }
+ /* Initialize parse state for recursive descent. */
+ data.declv = make_tree_vec (count);
+ data.initv = make_tree_vec (count);
+ data.condv = make_tree_vec (count);
+ data.incrv = make_tree_vec (count);
+ data.pre_body = NULL_TREE;;
+ data.bindings = NULL_TREE;
+ data.for_loc = c_parser_peek_token (parser)->location;
+ data.count = count;
+ data.depth = 0;
+ data.want_nested_loop = true;
+ data.ordered = ordered > 0;
+ data.in_intervening_code = false;
+ data.perfect_nesting_fail = false;
+ data.fail = false;
+ data.inscan = inscan;
+ data.code = code;
+ data.clauses = clauses;
+ parser->omp_for_parse_state = &data;
+
+ body = c_parser_omp_loop_nest (parser, if_p);
+
+ /* Add saved bindings for iteration variables that were declared in
+ the nested for loop to the scope surrounding the entire loop. */
+ for (tree t = data.bindings; t; )
+ {
+ tree n = TREE_CHAIN (t);
+ TREE_CHAIN (t) = NULL_TREE;
+ pushdecl (t);
+ t = n;
}
/* Only bother calling c_finish_omp_for if we haven't already generated
an error from the initialization parsing. */
- if (!fail)
+ if (!data.fail)
{
c_in_omp_for = true;
- stmt = c_finish_omp_for (loc, code, declv, NULL, initv, condv,
- incrv, body, pre_body, true);
+ stmt = c_finish_omp_for (loc, code, data.declv, NULL, data.initv,
+ data.condv, data.incrv,
+ body, data.pre_body, true);
c_in_omp_for = false;
/* Check for iterators appearing in lb, b or incr expressions. */
- if (stmt && !c_omp_check_loop_iv (stmt, declv, NULL))
+ if (stmt && !c_omp_check_loop_iv (stmt, data.declv, NULL))
stmt = NULL_TREE;
if (stmt)
@@ -20938,6 +21229,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
}
}
+ clauses = data.clauses;
if (cclauses != NULL
&& cclauses[C_OMP_CLAUSE_SPLIT_PARALLEL] != NULL)
{
@@ -20949,7 +21241,7 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
else
{
for (i = 0; i < count; i++)
- if (TREE_VEC_ELT (declv, i) == OMP_CLAUSE_DECL (*c))
+ if (TREE_VEC_ELT (data.declv, i) == OMP_CLAUSE_DECL (*c))
break;
if (i == count)
c = &OMP_CLAUSE_CHAIN (*c);
@@ -20962,7 +21254,8 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
}
else
{
- /* Move lastprivate (decl) clause to OMP_FOR_CLAUSES. */
+ /* Move lastprivate (decl) clause to
+ OMP_FOR_CLAUSES. */
tree l = *c;
*c = OMP_CLAUSE_CHAIN (*c);
if (code == OMP_SIMD)
@@ -20983,16 +21276,8 @@ c_parser_omp_for_loop (location_t loc, c_parser *parser, enum tree_code code,
}
ret = stmt;
}
-pop_scopes:
- while (!for_block->is_empty ())
- {
- /* FIXME diagnostics: LOC below should be the actual location of
- this particular for block. We need to build a list of
- locations to go along with FOR_BLOCK. */
- stmt = c_end_compound_stmt (loc, for_block->pop (), true);
- add_stmt (stmt);
- }
- release_tree_vector (for_block);
+
+ parser->omp_for_parse_state = save_data;
return ret;
}
new file mode 100644
@@ -0,0 +1,32 @@
+/* Functions for querying whether a function name is reserved by the
+ OpenMP API. This is used for error checking.
+
+ Copyright (C) 2023 Free Software Foundation, Inc.
+
+This file is part of GCC.
+
+GCC is free software; you can redistribute it and/or modify it under
+the terms of the GNU General Public License as published by the Free
+Software Foundation; either version 3, or (at your option) any later
+version.
+
+GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
+for more details.
+
+You should have received a copy of the GNU General Public License
+along with GCC; see the file COPYING3. If not see
+<http://www.gnu.org/licenses/>. */
+
+#ifndef GCC_OMP_API_H
+#define GCC_OMP_API_H
+
+#include "coretypes.h"
+
+/* In omp-general.cc, but declared in a separate header file for
+ convenience of the Fortran front end. */
+extern bool omp_runtime_api_procname (const char *name);
+extern bool omp_runtime_api_call (const_tree fndecl);
+
+#endif
@@ -3408,4 +3408,138 @@ omp_build_component_ref (tree obj, tree field)
return ret;
}
+/* Return true if NAME is the name of an omp_* runtime API call. */
+bool
+omp_runtime_api_procname (const char *name)
+{
+ if (!startswith (name, "omp_"))
+ return false;
+
+ static const char *omp_runtime_apis[] =
+ {
+ /* This array has 3 sections. First omp_* calls that don't
+ have any suffixes. */
+ "aligned_alloc",
+ "aligned_calloc",
+ "alloc",
+ "calloc",
+ "free",
+ "get_mapped_ptr",
+ "realloc",
+ "target_alloc",
+ "target_associate_ptr",
+ "target_disassociate_ptr",
+ "target_free",
+ "target_is_accessible",
+ "target_is_present",
+ "target_memcpy",
+ "target_memcpy_async",
+ "target_memcpy_rect",
+ "target_memcpy_rect_async",
+ NULL,
+ /* Now omp_* calls that are available as omp_* and omp_*_; however, the
+ DECL_NAME is always omp_* without tailing underscore. */
+ "capture_affinity",
+ "destroy_allocator",
+ "destroy_lock",
+ "destroy_nest_lock",
+ "display_affinity",
+ "fulfill_event",
+ "get_active_level",
+ "get_affinity_format",
+ "get_cancellation",
+ "get_default_allocator",
+ "get_default_device",
+ "get_device_num",
+ "get_dynamic",
+ "get_initial_device",
+ "get_level",
+ "get_max_active_levels",
+ "get_max_task_priority",
+ "get_max_teams",
+ "get_max_threads",
+ "get_nested",
+ "get_num_devices",
+ "get_num_places",
+ "get_num_procs",
+ "get_num_teams",
+ "get_num_threads",
+ "get_partition_num_places",
+ "get_place_num",
+ "get_proc_bind",
+ "get_supported_active_levels",
+ "get_team_num",
+ "get_teams_thread_limit",
+ "get_thread_limit",
+ "get_thread_num",
+ "get_wtick",
+ "get_wtime",
+ "in_explicit_task",
+ "in_final",
+ "in_parallel",
+ "init_lock",
+ "init_nest_lock",
+ "is_initial_device",
+ "pause_resource",
+ "pause_resource_all",
+ "set_affinity_format",
+ "set_default_allocator",
+ "set_lock",
+ "set_nest_lock",
+ "test_lock",
+ "test_nest_lock",
+ "unset_lock",
+ "unset_nest_lock",
+ NULL,
+ /* And finally calls available as omp_*, omp_*_ and omp_*_8_; however,
+ as DECL_NAME only omp_* and omp_*_8 appear. */
+ "display_env",
+ "get_ancestor_thread_num",
+ "init_allocator",
+ "get_partition_place_nums",
+ "get_place_num_procs",
+ "get_place_proc_ids",
+ "get_schedule",
+ "get_team_size",
+ "set_default_device",
+ "set_dynamic",
+ "set_max_active_levels",
+ "set_nested",
+ "set_num_teams",
+ "set_num_threads",
+ "set_schedule",
+ "set_teams_thread_limit"
+ };
+
+ int mode = 0;
+ for (unsigned i = 0; i < ARRAY_SIZE (omp_runtime_apis); i++)
+ {
+ if (omp_runtime_apis[i] == NULL)
+ {
+ mode++;
+ continue;
+ }
+ size_t len = strlen (omp_runtime_apis[i]);
+ if (strncmp (name + 4, omp_runtime_apis[i], len) == 0
+ && (name[4 + len] == '\0'
+ || (mode > 1 && strcmp (name + 4 + len, "_8") == 0)))
+ return true;
+ }
+ return false;
+}
+
+/* Return true if FNDECL is an omp_* runtime API call. */
+
+bool
+omp_runtime_api_call (const_tree fndecl)
+{
+ tree declname = DECL_NAME (fndecl);
+ if (!declname
+ || (DECL_CONTEXT (fndecl) != NULL_TREE
+ && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL)
+ || !TREE_PUBLIC (fndecl))
+ return false;
+ return omp_runtime_api_procname (IDENTIFIER_POINTER (declname));
+}
+
#include "gt-omp-general.h"
@@ -23,6 +23,7 @@ along with GCC; see the file COPYING3. If not see
#define GCC_OMP_GENERAL_H
#include "gomp-constants.h"
+#include "omp-api.h"
/* Flags for an OpenACC loop. */
@@ -4550,135 +4550,6 @@ setjmp_or_longjmp_p (const_tree fndecl)
return !strcmp (name, "setjmp") || !strcmp (name, "longjmp");
}
-/* Return true if FNDECL is an omp_* runtime API call. */
-
-static bool
-omp_runtime_api_call (const_tree fndecl)
-{
- tree declname = DECL_NAME (fndecl);
- if (!declname
- || (DECL_CONTEXT (fndecl) != NULL_TREE
- && TREE_CODE (DECL_CONTEXT (fndecl)) != TRANSLATION_UNIT_DECL)
- || !TREE_PUBLIC (fndecl))
- return false;
-
- const char *name = IDENTIFIER_POINTER (declname);
- if (!startswith (name, "omp_"))
- return false;
-
- static const char *omp_runtime_apis[] =
- {
- /* This array has 3 sections. First omp_* calls that don't
- have any suffixes. */
- "aligned_alloc",
- "aligned_calloc",
- "alloc",
- "calloc",
- "free",
- "get_mapped_ptr",
- "realloc",
- "target_alloc",
- "target_associate_ptr",
- "target_disassociate_ptr",
- "target_free",
- "target_is_accessible",
- "target_is_present",
- "target_memcpy",
- "target_memcpy_async",
- "target_memcpy_rect",
- "target_memcpy_rect_async",
- NULL,
- /* Now omp_* calls that are available as omp_* and omp_*_; however, the
- DECL_NAME is always omp_* without tailing underscore. */
- "capture_affinity",
- "destroy_allocator",
- "destroy_lock",
- "destroy_nest_lock",
- "display_affinity",
- "fulfill_event",
- "get_active_level",
- "get_affinity_format",
- "get_cancellation",
- "get_default_allocator",
- "get_default_device",
- "get_device_num",
- "get_dynamic",
- "get_initial_device",
- "get_level",
- "get_max_active_levels",
- "get_max_task_priority",
- "get_max_teams",
- "get_max_threads",
- "get_nested",
- "get_num_devices",
- "get_num_places",
- "get_num_procs",
- "get_num_teams",
- "get_num_threads",
- "get_partition_num_places",
- "get_place_num",
- "get_proc_bind",
- "get_supported_active_levels",
- "get_team_num",
- "get_teams_thread_limit",
- "get_thread_limit",
- "get_thread_num",
- "get_wtick",
- "get_wtime",
- "in_explicit_task",
- "in_final",
- "in_parallel",
- "init_lock",
- "init_nest_lock",
- "is_initial_device",
- "pause_resource",
- "pause_resource_all",
- "set_affinity_format",
- "set_default_allocator",
- "set_lock",
- "set_nest_lock",
- "test_lock",
- "test_nest_lock",
- "unset_lock",
- "unset_nest_lock",
- NULL,
- /* And finally calls available as omp_*, omp_*_ and omp_*_8_; however,
- as DECL_NAME only omp_* and omp_*_8 appear. */
- "display_env",
- "get_ancestor_thread_num",
- "init_allocator",
- "get_partition_place_nums",
- "get_place_num_procs",
- "get_place_proc_ids",
- "get_schedule",
- "get_team_size",
- "set_default_device",
- "set_dynamic",
- "set_max_active_levels",
- "set_nested",
- "set_num_teams",
- "set_num_threads",
- "set_schedule",
- "set_teams_thread_limit"
- };
-
- int mode = 0;
- for (unsigned i = 0; i < ARRAY_SIZE (omp_runtime_apis); i++)
- {
- if (omp_runtime_apis[i] == NULL)
- {
- mode++;
- continue;
- }
- size_t len = strlen (omp_runtime_apis[i]);
- if (strncmp (name + 4, omp_runtime_apis[i], len) == 0
- && (name[4 + len] == '\0'
- || (mode > 1 && strcmp (name + 4 + len, "_8") == 0)))
- return true;
- }
- return false;
-}
-
/* Helper function for scan_omp.
Callback for walk_gimple_stmt used to scan for OMP directives in
@@ -1,3 +1,17 @@
+2023-06-13 Sandra Loosemore <sandra@codesourcery.com>
+
+ * c-c++-common/goacc/collapse-1.c: Update for new C error behavior.
+ * c-c++-common/goacc/tile-2.c: Likewise.
+ * c-c++-common/gomp/loop-transforms/imperfect-loop-nest.c: Likewise.
+ * c-c++-common/gomp/loop-transforms/tile-1.c: Likewise.
+ * c-c++-common/gomp/loop-transforms/tile-2.c: Likewise.
+ * c-c++-common/gomp/loop-transforms/tile-3.c: Likewise.
+ * c-c++-common/gomp/loop-transforms/unroll-inner-2.c: Likewise.
+ * c-c++-common/gomp/metadirective-1.c: Likewise.
+ * gcc.dg/gomp/collapse-1.c: Likewise.
+ * gcc.dg/gomp/for-1.c: Likewise.
+ * gcc.dg/gomp/for-11.c: Likewise.
+
2023-06-12 Tobias Burnus <tobias@codesourcery.com>
Backported from mainline:
@@ -8,8 +8,8 @@ f1 (void)
{
#pragma acc parallel
#pragma acc loop collapse (2)
- for (i = 0; i < 5; i++)
- ; /* { dg-error "not enough perfectly nested" } */
+ for (i = 0; i < 5; i++) /* { dg-error "not enough nested loops" } */
+ ;
{
for (j = 0; j < 5; j++)
;
@@ -38,9 +38,9 @@ f3 (void)
{
#pragma acc parallel
#pragma acc loop collapse (2)
- for (i = 0; i < 5; i++)
+ for (i = 0; i < 5; i++) /* { dg-error "inner loops must be perfectly nested" } */
{
- int k = foo (); /* { dg-error "not enough perfectly nested" } */
+ int k = foo ();
{
{
for (j = 0; j < 5; j++)
@@ -56,12 +56,12 @@ f4 (void)
{
#pragma acc parallel
#pragma acc loop collapse (2)
- for (i = 0; i < 5; i++)
+ for (i = 0; i < 5; i++) /* { dg-error "inner loops must be perfectly nested" } */
{
{
for (j = 0; j < 5; j++)
;
- foo (); /* { dg-error "collapsed loops not perfectly nested before" } */
+ foo ();
}
}
}
@@ -71,13 +71,13 @@ f5 (void)
{
#pragma acc parallel
#pragma acc loop collapse (2)
- for (i = 0; i < 5; i++)
+ for (i = 0; i < 5; i++) /* { dg-error "inner loops must be perfectly nested" } */
{
{
for (j = 0; j < 5; j++)
;
}
- foo (); /* { dg-error "collapsed loops not perfectly nested before" } */
+ foo ();
}
}
@@ -3,8 +3,8 @@ int main ()
#pragma acc parallel
{
#pragma acc loop tile (*,*)
- for (int ix = 0; ix < 30; ix++)
- ; /* { dg-error "not enough" } */
+ for (int ix = 0; ix < 30; ix++) /* { dg-error "not enough" "" { target c } } */
+ ; /* { dg-error "not enough" "" { target c++ } } */
#pragma acc loop tile (*,*)
for (int ix = 0; ix < 30; ix++)
@@ -1,11 +1,11 @@
void test ()
{
#pragma omp tile sizes (2,4,6)
- for (unsigned i = 0; i < 10; i++)
+ for (unsigned i = 0; i < 10; i++) /* { dg-error "inner loops must be perfectly nested" { target c } } */
for (unsigned j = 0; j < 10; j++)
{
float intervening_decl = 0; /* { dg-bogus "not enough for loops to collapse" "TODO C/C++ imperfect loop nest handling" { xfail c++ } } */
- /* { dg-bogus "not enough perfectly nested loops" "TODO C/C++ imperfect loop nest handling" { xfail c } .-1 } */
+
#pragma omp unroll partial(2)
for (unsigned k = 0; k < 10; k++);
}
@@ -110,9 +110,9 @@ test ()
dummy (i);
#pragma omp tile sizes(1, 2, 3)
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} "" { target c } } */
for (int j = 0; j < 100; ++j)
- dummy (i); /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } } */
+ dummy (i);
/* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
/* { dg-error {'i' was not declared in this scope} "" { target c++ } .-2 } */
@@ -133,20 +133,20 @@ test ()
}
#pragma omp tile sizes(1, 2)
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} "" { target c } } */
{
- dummy (i); /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } } */
+ dummy (i);
/* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
for (int j = 0; j < 100; ++j)
dummy (j);
}
#pragma omp tile sizes(1, 2)
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} "" { target c } } */
{
for (int j = 0; j < 100; ++j)
dummy (j);
- dummy (i); /* { dg-error {collapsed loops not perfectly nested before 'dummy'} "" { target c} } */
+ dummy (i);
/* { dg-error {collapsed loops not perfectly nested} "" { target c++ } .-1 } */
}
@@ -132,9 +132,9 @@ test ()
#pragma omp parallel for
#pragma omp tile sizes(1, 2, 3)
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} "" { target c } } */
for (int j = 0; j < 100; ++j)
- dummy (i); /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } } */
+ dummy (i);
/* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
/* { dg-error {'i' was not declared in this scope} "" { target c++ } .-2 } */
@@ -158,9 +158,9 @@ test ()
#pragma omp parallel for
#pragma omp tile sizes(1, 2)
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} "" { target c } } */
{
- dummy (i); /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } } */
+ dummy (i);
/* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
for (int j = 0; j < 100; ++j)
dummy (j);
@@ -168,11 +168,11 @@ test ()
#pragma omp parallel for
#pragma omp tile sizes(1, 2)
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 100; ++i) /* { dg-error {inner loops must be perfectly nested} "" { target c } } */
{
for (int j = 0; j < 100; ++j)
dummy (j);
- dummy (i); /* { dg-error {collapsed loops not perfectly nested before 'dummy'} "" { target c} } */
+ dummy (i);
/* { dg-error {collapsed loops not perfectly nested} "" { target c++ } .-1 } */
}
@@ -36,12 +36,11 @@ test ()
#pragma omp for collapse(3)
#pragma omp tile sizes(1, 2) /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} "" { target c } } */
for (int j = 0; j < 100; ++j)
dummy (i);
- /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } .-1 } */
- /* { dg-error {not enough for loops to collapse} "" { target c++ } .-2 } */
- /* { dg-error {'i' was not declared in this scope} "" { target c++ } .-3 } */
+ /* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
+ /* { dg-error {'i' was not declared in this scope} "" { target c++ } .-2 } */
#pragma omp for collapse(1)
#pragma omp tile sizes(1)
@@ -52,25 +51,24 @@ test ()
#pragma omp for collapse(2)
#pragma omp tile sizes(1, 2)
#pragma omp tile sizes(1) /* { dg-error {nesting depth left after this transformation too low for outer transformation} } */
- for (int i = 0; i < 100; ++i)
- dummy (i); /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } } */
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} "" { target c } } */
+ dummy (i);
/* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
#pragma omp for collapse(2)
#pragma omp tile sizes(1, 2)
#pragma omp tile sizes(1, 2)
- for (int i = 0; i < 100; ++i)
- dummy (i); /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } } */
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} "" { target c } } */
+ dummy (i);
/* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
#pragma omp for collapse(2)
#pragma omp tile sizes(5, 6)
#pragma omp tile sizes(1, 2, 3)
- for (int i = 0; i < 100; ++i)
- dummy (i); /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } } */
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} "" { target c } } */
+ dummy (i);
/* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
-
#pragma omp for collapse(1)
#pragma omp tile sizes(1)
#pragma omp tile sizes(1)
@@ -102,9 +100,9 @@ test ()
#pragma omp for collapse(3)
#pragma omp tile sizes(1, 2) /* { dg-error {nesting depth left after this transformation too low for loop collapse} } */
#pragma omp tile sizes(1, 2)
- for (int i = 0; i < 100; ++i)
+ for (int i = 0; i < 100; ++i) /* { dg-error {not enough nested loops} "" { target c } } */
for (int j = 0; j < 100; ++j)
- dummy (i); /* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } } */
+ dummy (i);
/* { dg-error {not enough for loops to collapse} "" { target c++ } .-1 } */
#pragma omp for collapse(3)
@@ -13,12 +13,11 @@ test ()
dummy (i);
#pragma omp target parallel for collapse(2)
- for (int i = -300; i != 100; ++i)
+ for (int i = -300; i != 100; ++i) /* { dg-error {not enough nested loops} "" { target c } } */
#pragma omp tile sizes(2, 3)
for (int j = 0; j != 100; ++j)
dummy (i); /* { dg-error {not enough for loops to collapse} "" { target c++ } } */
/* { dg-error {'i' was not declared in this scope} "" { target c++ } .-1 } */
-/* { dg-error {not enough perfectly nested loops before 'dummy'} "" { target c } .-2 } */
#pragma omp target parallel for collapse(2)
for (int i = -300; i != 100; ++i)
@@ -36,7 +36,7 @@ void f (int a[], int b[], int c[])
when (implementation={vendor("gnu")}: parallel for)
#pragma omp metadirective \
when (implementation={vendor("cray")}: parallel for)
- /* { dg-error "for statement expected before '#pragma'" "" { target c } .-2 } */
+ /* { dg-error "loop nest expected before '#pragma'" "" { target c } .-2 } */
/* { dg-error "'#pragma' is not allowed here" "" { target c++ } .-3 } */
for (i = 0; i < N; i++) c[i] = a[i] * b[i];
}
@@ -8,8 +8,8 @@ void
f1 (void)
{
#pragma omp for collapse (2)
- for (i = 0; i < 5; i++)
- ; /* { dg-error "not enough perfectly nested" } */
+ for (i = 0; i < 5; i++) /* { dg-error "not enough nested loops" } */
+ ;
{
for (j = 0; j < 5; j++)
;
@@ -38,7 +38,7 @@ f3 (void)
#pragma omp for collapse (2)
for (i = 0; i < 5; i++)
{
- int k = foo (); /* { dg-error "not enough perfectly nested" } */
+ int k = foo ();
{
{
for (j = 0; j < 5; j++)
@@ -58,7 +58,7 @@ f4 (void)
{
for (j = 0; j < 5; j++)
;
- foo (); /* { dg-error "collapsed loops not perfectly nested before" } */
+ foo ();
}
}
}
@@ -73,7 +73,7 @@ f5 (void)
for (j = 0; j < 5; j++)
;
}
- foo (); /* { dg-error "collapsed loops not perfectly nested before" } */
+ foo ();
}
}
@@ -26,7 +26,7 @@ void foo (int j, int k)
/* Malformed parallel loops. */
#pragma omp for
- i = 0; /* { dg-error "3:for statement expected" } */
+ i = 0; /* { dg-error "loop nest expected" } */
for ( ; i < 10; )
{
baz (i);
@@ -30,7 +30,7 @@ void foo (int j, int k)
/* Malformed parallel loops. */
#pragma omp for
- i = 0; /* { dg-error "for statement expected" } */
+ i = 0; /* { dg-error "loop nest expected" } */
for ( ; i < 10; )
{
baz (i);