summaryrefslogtreecommitdiff
path: root/gcc/cp/parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/parser.cc')
-rw-r--r--gcc/cp/parser.cc290
1 files changed, 239 insertions, 51 deletions
diff --git a/gcc/cp/parser.cc b/gcc/cp/parser.cc
index 1c4450b337a..230aec51886 100644
--- a/gcc/cp/parser.cc
+++ b/gcc/cp/parser.cc
@@ -43005,7 +43005,8 @@ cp_parser_omp_scan_loop_body (cp_parser *parser)
braces.require_close (parser);
}
-static bool cp_parser_nested_omp_unroll_clauses (cp_parser *, tree &);
+static int cp_parser_omp_nested_loop_transform_clauses (cp_parser *, tree &,
+ int, const char *);
/* Parse the restricted form of the for statement allowed by OpenMP. */
@@ -43017,20 +43018,20 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
tree orig_decl;
tree real_decl, initv, condv, incrv, declv, orig_declv;
tree this_pre_body, cl, ordered_cl = NULL_TREE;
- location_t loc_first;
bool collapse_err = false;
int i, collapse = 1, ordered = 0, count, nbraces = 0;
releasing_vec for_block;
auto_vec<tree, 4> orig_inits;
- bool tiling = false;
+ bool oacc_tiling = false;
bool inscan = false;
+ location_t loc_first = cp_lexer_peek_token (parser->lexer)->location;
for (cl = clauses; cl; cl = OMP_CLAUSE_CHAIN (cl))
if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_COLLAPSE)
collapse = tree_to_shwi (OMP_CLAUSE_COLLAPSE_EXPR (cl));
else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_OACC_TILE)
{
- tiling = true;
+ oacc_tiling = true;
collapse = list_length (OMP_CLAUSE_OACC_TILE_LIST (cl));
}
else if (OMP_CLAUSE_CODE (cl) == OMP_CLAUSE_ORDERED
@@ -43053,26 +43054,33 @@ cp_parser_omp_for_loop (cp_parser *parser, enum tree_code code, tree clauses,
ordered = collapse;
}
- gcc_assert (tiling || (collapse >= 1 && ordered >= 0));
+
+ gcc_assert (oacc_tiling || (collapse >= 1 && ordered >= 0));
count = ordered ? ordered : collapse;
+ cp_parser_omp_nested_loop_transform_clauses (parser, clauses, count,
+ "loop collapse");
+
+ /* Find the depth of the loop nest affected by "omp tile"
+ directives. There can be several such directives, but the tiling
+ depth of the outer ones may not be larger than the depth of the
+ innermost directive. */
+ int omp_tile_depth = 0;
+ for (tree c = clauses; c; c = TREE_CHAIN (c))
+ {
+ if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_TILE)
+ continue;
+
+ omp_tile_depth = list_length (OMP_CLAUSE_TILE_SIZES (c));
+ }
+ 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);
orig_declv = NULL_TREE;
- loc_first = cp_lexer_peek_token (parser->lexer)->location;
-
- if (cp_parser_nested_omp_unroll_clauses (parser, clauses)
- && count > 1)
- {
- error_at (loc_first,
- "collapse cannot be larger than 1 on an unrolled loop");
- return NULL;
- }
-
-
for (i = 0; i < count; i++)
{
int bracecount = 0;
@@ -45137,51 +45145,225 @@ cp_parser_omp_target (cp_parser *parser, cp_token *pragma_tok,
return true;
}
+
+/* OpenMP 5.1: Parse sizes list for "omp tile sizes"
+ sizes ( size-expr-list ) */
+static tree
+cp_parser_omp_tile_sizes (cp_parser *parser, location_t loc)
+{
+ tree sizes = NULL_TREE;
+ cp_lexer *lexer = parser->lexer;
+
+ cp_token *tok = cp_lexer_peek_token (lexer);
+ if (tok->type != CPP_NAME
+ || strcmp ("sizes", IDENTIFIER_POINTER (tok->u.value)))
+ {
+ cp_parser_error (parser, "expected %<sizes%>");
+ return error_mark_node;
+ }
+ cp_lexer_consume_token (lexer);
+
+ if (!cp_parser_require (parser, CPP_OPEN_PAREN, RT_OPEN_PAREN))
+ return error_mark_node;
+
+ do
+ {
+ if (sizes && !cp_parser_require (parser, CPP_COMMA, RT_COMMA))
+ return error_mark_node;
+
+ tree expr = cp_parser_constant_expression (parser);
+ if (expr == error_mark_node)
+ {
+ cp_parser_skip_to_closing_parenthesis (parser,
+ /*recovering=*/true,
+ /*or_comma=*/false,
+ /*consume_paren=*/
+ true);
+ return error_mark_node;
+ }
+
+ sizes = tree_cons (NULL_TREE, expr, sizes);
+ }
+ while (cp_lexer_next_token_is_not (lexer, CPP_CLOSE_PAREN));
+ cp_lexer_consume_token (lexer);
+
+ gcc_assert (sizes);
+ tree c = build_omp_clause (loc, OMP_CLAUSE_TILE);
+ OMP_CLAUSE_TILE_SIZES (c) = sizes;
+
+ return c;
+}
+
+/* OpenMP 5.1:
+ tile sizes ( size-expr-list ) */
+
+static tree
+cp_parser_omp_tile (cp_parser *parser, cp_token *tok, bool *if_p)
+{
+ tree block;
+ tree ret = error_mark_node;
+
+ tree clauses = cp_parser_omp_tile_sizes (parser, tok->location);
+ cp_parser_require_pragma_eol (parser, tok);
+
+ if (!clauses || clauses == error_mark_node)
+ return error_mark_node;
+
+ int required_depth = list_length (OMP_CLAUSE_TILE_SIZES (clauses));
+ cp_parser_omp_nested_loop_transform_clauses (
+ parser, clauses, required_depth, "outer transformation");
+
+ block = begin_omp_structured_block ();
+ clauses = finish_omp_clauses (clauses, C_ORT_OMP);
+
+ ret = cp_parser_omp_for_loop (parser, OMP_LOOP_TRANS, clauses, NULL, if_p);
+ block = finish_omp_structured_block (block);
+ add_stmt (block);
+
+ return ret;
+}
+
#define OMP_UNROLL_CLAUSE_MASK \
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_PARTIAL) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_FULL) )
-/* Parse zero or more '#pragma omp unroll' that follow
- another directive that requires a canonical loop nest. */
+/* Parse a single OpenMP loop transformation directive and return the
+ clause that is used internally to represent the directive. */
-static bool
-cp_parser_nested_omp_unroll_clauses (cp_parser *parser, tree &clauses)
+static tree
+cp_parser_omp_loop_transform_clause (cp_parser *parser)
{
- static const char *p_name = "#pragma omp unroll";
- cp_token *tok;
- bool unroll_found = false;
- while (cp_lexer_next_token_is (parser->lexer, CPP_PRAGMA)
- && (tok = cp_lexer_peek_token (parser->lexer),
- cp_parser_pragma_kind (tok) == PRAGMA_OMP_UNROLL))
+ cp_lexer *lexer = parser->lexer;
+ cp_token *tok = cp_lexer_peek_token (lexer);
+ if (tok->type != CPP_PRAGMA)
+ return NULL_TREE;
+
+ tree c;
+ switch (cp_parser_pragma_kind (tok))
{
- cp_lexer_consume_token (parser->lexer);
- gcc_assert (tok->type == CPP_PRAGMA);
- parser->lexer->in_pragma = true;
- tree c = cp_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK,
- p_name, tok);
- if (c)
- {
- gcc_assert (!TREE_CHAIN (c));
- unroll_found = true;
- if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_UNROLL_FULL)
- {
- error_at (tok->location, "%<full%> clause is invalid here; "
- "turns loop into non-loop");
- continue;
- }
+ case PRAGMA_OMP_UNROLL:
+ cp_lexer_consume_token (lexer);
+ lexer->in_pragma = true;
+ c = cp_parser_omp_all_clauses (parser, OMP_UNROLL_CLAUSE_MASK,
+ "#pragma omp unroll", tok,
+ false, true);
+ if (!c)
+ {
+ if (cp_lexer_next_token_is (lexer, CPP_PRAGMA_EOL))
+ c = build_omp_clause (tok->location, OMP_CLAUSE_UNROLL_NONE);
+ else
+ c = error_mark_node;
+ }
+ cp_parser_skip_to_pragma_eol (parser, tok);
+ break;
+
+ case PRAGMA_OMP_TILE:
+ cp_lexer_consume_token (lexer);
+ lexer->in_pragma = true;
+ c = cp_parser_omp_tile_sizes (parser, tok->location);
+ cp_parser_require_pragma_eol (parser, tok);
+ break;
+
+ default:
+ c = NULL_TREE;
+ break;
+ }
+
+ gcc_assert (!c || !TREE_CHAIN (c));
+ return c;
+}
+
+/* Parse zero or more OpenMP loop transformation directives that
+ follow another directive that requires a canonical loop nest and
+ append all to CLAUSES. Return the nesting depth
+ of the transformed loop nest.
+
+ REQUIRED_DEPTH is the nesting depth of the loop nest required by
+ the preceding directive. OUTER_DESCR is a description of the
+ language construct that requires the loop nest depth (e.g. "loop
+ collpase", "outer transformation") that is used for error
+ messages. */
- c = finish_omp_clauses (c, C_ORT_OMP);
+static int
+cp_parser_omp_nested_loop_transform_clauses (cp_parser *parser, tree &clauses,
+ int required_depth,
+ const char *outer_descr)
+{
+ tree c = NULL_TREE;
+ tree last_c = tree_last (clauses);
+
+ /* The depth of the loop nest after the transformations. That is,
+ the nesting depth left by the outermost transformation which is
+ the first to be parsed, but the last to be executed. */
+ int transformed_depth = 0;
+
+ /* The minimum nesting depth required by the last parsed transformation. */
+ int last_depth = required_depth;
+
+ while ((c = cp_parser_omp_loop_transform_clause (parser)))
+ {
+ /* The nesting depth left after the current transformation */
+ int depth = 1;
+ if (TREE_CODE (c) == ERROR_MARK)
+ goto error;
+
+ gcc_assert (!TREE_CHAIN (c));
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_UNROLL_FULL:
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<full%> clause is invalid here; "
+ "turns loop into non-loop");
+ goto error;
+ case OMP_CLAUSE_UNROLL_NONE:
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%<#pragma omp unroll%> without "
+ "%<partial%> clause is invalid here; "
+ "turns loop into non-loop");
+ goto error;
+ case OMP_CLAUSE_UNROLL_PARTIAL:
+ depth = 1;
+ break;
+ case OMP_CLAUSE_TILE:
+ depth = list_length (OMP_CLAUSE_TILE_SIZES (c));
+ break;
+ default:
+ gcc_unreachable ();
}
- else
+
+ if (depth < last_depth)
{
- error_at (tok->location, "%<#pragma omp unroll%> without "
- "%<partial%> clause is invalid here; "
- "turns loop into non-loop");
- continue;
+ bool is_outermost_clause = !transformed_depth;
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "nesting depth left after this transformation too low "
+ "for %s",
+ is_outermost_clause ? outer_descr
+ : "outer transformation");
+ goto error;
}
- clauses = chainon (clauses, c);
+
+ last_depth = depth;
+
+ if (!transformed_depth)
+ transformed_depth = last_depth;
+
+ c = finish_omp_clauses (c, C_ORT_OMP);
+
+ if (!clauses)
+ clauses = c;
+ else if (last_c)
+ TREE_CHAIN (last_c) = c;
+
+ last_c = c;
}
- return unroll_found;
+
+ return transformed_depth;
+
+error:
+ while (cp_parser_omp_loop_transform_clause (parser))
+ ;
+ clauses = NULL_TREE;
+ return -1;
}
static tree
@@ -45191,7 +45373,7 @@ cp_parser_omp_unroll (cp_parser *parser, cp_token *tok, bool *if_p)
static const char *p_name = "#pragma omp unroll";
omp_clause_mask mask = OMP_UNROLL_CLAUSE_MASK;
- tree clauses = cp_parser_omp_all_clauses (parser, mask, p_name, tok, false);
+ tree clauses = cp_parser_omp_all_clauses (parser, mask, p_name, tok, true);
if (!clauses)
{
@@ -45200,7 +45382,9 @@ cp_parser_omp_unroll (cp_parser *parser, cp_token *tok, bool *if_p)
clauses = c;
}
- cp_parser_nested_omp_unroll_clauses (parser, clauses);
+ int required_depth = 1;
+ cp_parser_omp_nested_loop_transform_clauses (
+ parser, clauses, required_depth, "outer transformation");
block = begin_omp_structured_block ();
ret = cp_parser_omp_for_loop (parser, OMP_LOOP_TRANS, clauses, NULL, if_p);
@@ -48728,6 +48912,9 @@ cp_parser_omp_construct (cp_parser *parser, cp_token *pragma_tok, bool *if_p)
case PRAGMA_OMP_ASSUME:
cp_parser_omp_assume (parser, pragma_tok, if_p);
return;
+ case PRAGMA_OMP_TILE:
+ stmt = cp_parser_omp_tile (parser, pragma_tok, if_p);
+ break;
case PRAGMA_OMP_UNROLL:
stmt = cp_parser_omp_unroll (parser, pragma_tok, if_p);
break;
@@ -49361,6 +49548,7 @@ cp_parser_pragma (cp_parser *parser, enum pragma_context context, bool *if_p)
cp_parser_omp_construct (parser, pragma_tok, if_p);
pop_omp_privatization_clauses (stmt);
return true;
+ case PRAGMA_OMP_TILE:
case PRAGMA_OMP_UNROLL:
if (context != pragma_stmt && context != pragma_compound)
goto bad_stmt;