aboutsummaryrefslogtreecommitdiff
path: root/gcc/c/c-parser.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c/c-parser.cc')
-rw-r--r--gcc/c/c-parser.cc2391
1 files changed, 2222 insertions, 169 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 22ec0f8..9af7440 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -1456,6 +1456,55 @@ c_parser_skip_to_pragma_eol (c_parser *parser, bool error_if_not_eol = true)
parser->error = false;
}
+/* Skip tokens up to and including "#pragma omp end declare variant".
+ Properly handle nested "#pragma omp begin declare variant" pragmas. */
+static void
+c_parser_skip_to_pragma_omp_end_declare_variant (c_parser *parser)
+{
+ for (int depth = 0; depth >= 0; )
+ {
+ c_token *token = c_parser_peek_token (parser);
+
+ switch (token->type)
+ {
+ case CPP_PRAGMA_EOL:
+ if (!parser->in_pragma)
+ break;
+ /* FALLTHRU */
+ case CPP_EOF:
+ /* If we've run out of tokens, stop. */
+ return;
+
+ case CPP_PRAGMA:
+ if ((token->pragma_kind == PRAGMA_OMP_BEGIN
+ || token->pragma_kind == PRAGMA_OMP_END)
+ && c_parser_peek_nth_token (parser, 2)->type == CPP_NAME
+ && c_parser_peek_nth_token (parser, 3)->type == CPP_NAME)
+ {
+ tree id1 = c_parser_peek_nth_token (parser, 2)->value;
+ tree id2 = c_parser_peek_nth_token (parser, 3)->value;
+ if (strcmp (IDENTIFIER_POINTER (id1), "declare") == 0
+ && strcmp (IDENTIFIER_POINTER (id2), "variant") == 0)
+ {
+ if (token->pragma_kind == PRAGMA_OMP_BEGIN)
+ depth++;
+ else
+ depth--;
+ }
+ }
+ c_parser_consume_pragma (parser);
+ c_parser_skip_to_pragma_eol (parser, false);
+ continue;
+
+ default:
+ break;
+ }
+
+ /* Consume the token. */
+ c_parser_consume_token (parser);
+ }
+}
+
/* Skip tokens until we have consumed an entire block, or until we
have consumed a non-nested ';'. */
@@ -1979,6 +2028,13 @@ c_parser_translation_unit (c_parser *parser)
"#pragma omp end declare target");
vec_safe_truncate (current_omp_declare_target_attribute, 0);
}
+ if (vec_safe_length (current_omp_declare_variant_attribute))
+ {
+ if (!errorcount)
+ error ("%<omp begin declare variant%> without corresponding "
+ "%<omp end declare variant%>");
+ vec_safe_truncate (current_omp_declare_variant_attribute, 0);
+ }
if (vec_safe_length (current_omp_begin_assumes))
{
if (!errorcount)
@@ -2112,6 +2168,8 @@ static void c_parser_handle_directive_omp_attributes (tree &, vec<c_token> *&,
vec<c_token> *);
static void c_finish_omp_declare_simd (c_parser *, tree, tree, vec<c_token> *);
static void c_finish_oacc_routine (struct oacc_routine_data *, tree, bool);
+static tree omp_start_variant_function (c_declarator *, tree);
+static void omp_finish_variant_function (tree, tree, tree);
/* Build and add a DEBUG_BEGIN_STMT statement with location LOC. */
@@ -3064,6 +3122,21 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
pedwarn (here, OPT_Wpedantic, "ISO C forbids nested functions");
c_push_function_context ();
}
+
+ /* If we're in an OpenMP "begin declare variant" block, the
+ name in the declarator refers to the base function. We need
+ to save that and modify the declarator to have the mangled
+ name for the variant function instead. */
+ tree dv_base = NULL_TREE;
+ tree dv_ctx = NULL_TREE;
+ if (!vec_safe_is_empty (current_omp_declare_variant_attribute))
+ {
+ c_omp_declare_variant_attr a
+ = current_omp_declare_variant_attribute->last ();
+ dv_ctx = copy_list (a.selector);
+ dv_base = omp_start_variant_function (declarator, dv_ctx);
+ }
+
if (!start_function (specs, declarator, all_prefix_attrs))
{
/* At this point we've consumed:
@@ -3141,6 +3214,11 @@ c_parser_declaration_or_fndef (c_parser *parser, bool fndef_ok,
DECL_STRUCT_FUNCTION (current_function_decl)->function_start_locus
= startloc;
location_t endloc = startloc;
+ /* If this function was in a "begin declare variant" block,
+ store the pointer back to the base function and fix up
+ the attributes for the middle end. */
+ if (dv_base && current_function_decl != error_mark_node)
+ omp_finish_variant_function (current_function_decl, dv_base, dv_ctx);
/* If the definition was marked with __RTL, use the RTL parser now,
consuming the function body. */
@@ -6438,7 +6516,9 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p,
gcc_obstack_init (&braced_init_obstack);
gcc_assert (c_parser_next_token_is (parser, CPP_OPEN_BRACE));
bool save_c_omp_array_section_p = c_omp_array_section_p;
+ bool save_c_omp_array_shaping_op_p = c_omp_array_shaping_op_p;
c_omp_array_section_p = false;
+ c_omp_array_shaping_op_p = false;
bool zero_init_padding_bits = false;
matching_braces braces;
braces.consume_open (parser);
@@ -6500,6 +6580,7 @@ c_parser_braced_init (c_parser *parser, tree type, bool nested_p,
}
}
c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
c_token *next_tok = c_parser_peek_token (parser);
if (next_tok->type != CPP_CLOSE_BRACE)
{
@@ -9900,6 +9981,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
struct c_expr cond, exp1, exp2, ret;
location_t start, cond_loc, colon_loc;
bool save_c_omp_array_section_p = c_omp_array_section_p;
+ bool save_c_omp_array_shaping_op_p = c_omp_array_shaping_op_p;
gcc_assert (!after || c_dialect_objc ());
@@ -9908,6 +9990,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
if (c_parser_next_token_is_not (parser, CPP_QUERY))
return cond;
c_omp_array_section_p = false;
+ c_omp_array_shaping_op_p = false;
if (cond.value != error_mark_node)
start = cond.get_start ();
else
@@ -9961,6 +10044,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
return ret;
}
{
@@ -10008,6 +10092,7 @@ c_parser_conditional_expression (c_parser *parser, struct c_expr *after,
set_c_expr_source_range (&ret, start, exp2.get_finish ());
ret.m_decimal = 0;
c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
return ret;
}
@@ -10389,6 +10474,8 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
if (after)
return c_parser_postfix_expression_after_primary (parser,
cast_loc, *after);
+ bool save_c_omp_has_array_shape_p = c_omp_has_array_shape_p;
+ c_omp_has_array_shape_p = false;
/* If the expression begins with a parenthesized type name, it may
be either a cast or a compound literal; we need to see whether
the next character is '{' to tell the difference. If not, it is
@@ -10397,6 +10484,10 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
if (c_parser_next_token_is (parser, CPP_OPEN_PAREN)
&& c_token_starts_compound_literal (c_parser_peek_2nd_token (parser)))
{
+ bool save_c_omp_array_section_p = c_omp_array_section_p;
+ bool save_c_omp_array_shaping_op_p = c_omp_array_shaping_op_p;
+ c_omp_array_section_p = false;
+ c_omp_array_shaping_op_p = false;
struct c_declspecs *scspecs;
struct c_type_name *type_name;
struct c_expr ret;
@@ -10408,6 +10499,8 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
parens.skip_until_found_close (parser);
if (type_name == NULL)
{
+ c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
ret.set_error ();
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
@@ -10418,9 +10511,15 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
used_types_insert (type_name->specs->type);
if (c_parser_next_token_is (parser, CPP_OPEN_BRACE))
- return c_parser_postfix_expression_after_paren_type (parser, scspecs,
- type_name,
- cast_loc);
+ {
+ c_expr r = c_parser_postfix_expression_after_paren_type (parser,
+ scspecs,
+ type_name,
+ cast_loc);
+ c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
+ return r;
+ }
if (scspecs)
error_at (cast_loc, "storage class specifier in cast");
if (type_name->specs->alignas_p)
@@ -10437,10 +10536,61 @@ c_parser_cast_expression (c_parser *parser, struct c_expr *after)
ret.original_code = ERROR_MARK;
ret.original_type = NULL;
ret.m_decimal = 0;
+ c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
+ return ret;
+ }
+ else if (c_omp_array_shaping_op_p
+ && c_parser_next_token_is (parser, CPP_OPEN_PAREN)
+ && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_SQUARE)
+ {
+ bool save_c_omp_array_section_p = c_omp_array_section_p;
+ bool save_c_omp_array_shaping_op_p = c_omp_array_shaping_op_p;
+ c_omp_array_section_p = false;
+ c_omp_array_shaping_op_p = false;
+ auto_vec<tree, 4> omp_shape_dims;
+ struct c_expr expr, ret;
+ matching_parens parens;
+ parens.consume_open (parser);
+ while (c_parser_next_token_is (parser, CPP_OPEN_SQUARE))
+ {
+ c_parser_consume_token (parser);
+ c_expr e = c_parser_expression (parser);
+ if (e.value == error_mark_node)
+ break;
+ omp_shape_dims.safe_push (e.value);
+ if (!c_parser_require (parser, CPP_CLOSE_SQUARE,
+ "expected %<]%>"))
+ break;
+ }
+ parens.require_close (parser);
+ c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
+ {
+ location_t expr_loc = c_parser_peek_token (parser)->location;
+ bool save_c_omp_has_array_shape_p = c_omp_has_array_shape_p;
+ c_omp_has_array_shape_p = true;
+ expr = c_parser_cast_expression (parser, NULL);
+ c_omp_has_array_shape_p = save_c_omp_has_array_shape_p;
+ /* NOTE: We don't want to introduce conversions here. */
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ }
+ tree arrtype
+ = create_omp_arrayshape_type (expr.value, &omp_shape_dims);
+ ret.value = build1_loc (cast_loc, VIEW_CONVERT_EXPR, arrtype,
+ expr.value);
+ if (ret.value && expr.value)
+ set_c_expr_source_range (&ret, cast_loc, expr.get_finish ());
+ ret.original_code = ERROR_MARK;
+ ret.original_type = NULL;
+ ret.m_decimal = 0;
return ret;
}
else
- return c_parser_unary_expression (parser);
+ {
+ c_omp_has_array_shape_p = save_c_omp_has_array_shape_p;
+ return c_parser_unary_expression (parser);
+ }
}
/* Parse an unary expression (C90 6.3.3, C99 6.5.3, C11 6.5.3).
@@ -11528,6 +11678,7 @@ c_parser_postfix_expression (c_parser *parser)
tree stmt;
location_t brace_loc;
bool save_c_omp_array_section_p = c_omp_array_section_p;
+ bool save_c_omp_array_shaping_op_p = c_omp_array_shaping_op_p;
c_parser_consume_token (parser);
brace_loc = c_parser_peek_token (parser)->location;
c_parser_consume_token (parser);
@@ -11545,6 +11696,7 @@ c_parser_postfix_expression (c_parser *parser)
break;
}
c_omp_array_section_p = false;
+ c_omp_array_shaping_op_p = false;
stmt = c_begin_stmt_expr ();
c_parser_compound_statement_nostart (parser);
location_t close_loc = c_parser_peek_token (parser)->location;
@@ -11556,6 +11708,7 @@ c_parser_postfix_expression (c_parser *parser)
set_c_expr_source_range (&expr, loc, close_loc);
mark_exp_read (expr.value);
c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
}
else
{
@@ -13628,15 +13781,38 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
if (c_omp_array_section_p
&& c_parser_next_token_is (parser, CPP_COLON))
{
+ tree stride = NULL_TREE;
+
c_parser_consume_token (parser);
if (c_parser_next_token_is_not (parser, CPP_CLOSE_SQUARE))
len = c_parser_expression (parser).value;
+ if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is_not (parser, CPP_CLOSE_SQUARE))
+ stride = c_parser_expression (parser).value;
+ }
+
expr.value = build_omp_array_section (op_loc, expr.value, idx,
- len);
+ len, stride);
}
else
- expr.value = build_array_ref (op_loc, expr.value, idx);
+ {
+ if (c_omp_has_array_shape_p)
+ /* If we have an array-shaping operator, we may not be able to
+ represent a well-formed ARRAY_REF here, because we are
+ coercing the type of the innermost array base and the
+ original type may not be compatible. Use the
+ OMP_ARRAY_SECTION code instead. We also want to explicitly
+ avoid creating INDIRECT_REFs for pointer bases, because
+ that can lead to parsing ambiguities (see
+ c_parser_omp_variable_list). */
+ expr.value = build_omp_array_section (op_loc, expr.value, idx,
+ size_one_node, NULL_TREE);
+ else
+ expr.value = build_array_ref (op_loc, expr.value, idx);
+ }
c_parser_skip_until_found (parser, CPP_CLOSE_SQUARE,
"expected %<]%>");
@@ -13834,8 +14010,8 @@ c_parser_postfix_expression_after_primary (c_parser *parser,
finish = c_parser_peek_token (parser)->get_finish ();
c_parser_consume_token (parser);
expr = default_function_array_read_conversion (expr_loc, expr);
- expr.value = build_unary_op (op_loc, POSTINCREMENT_EXPR,
- expr.value, false);
+ expr.value
+ = build_unary_op (op_loc, POSTINCREMENT_EXPR, expr.value, false);
set_c_expr_source_range (&expr, start, finish);
expr.original_code = ERROR_MARK;
expr.original_type = NULL;
@@ -13987,7 +14163,9 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
struct c_expr expr;
unsigned int idx = 0;
bool save_c_omp_array_section_p = c_omp_array_section_p;
+ bool save_c_omp_array_shaping_op_p = c_omp_array_shaping_op_p;
c_omp_array_section_p = false;
+ c_omp_array_shaping_op_p = false;
ret = make_tree_vector ();
if (p_orig_types == NULL)
@@ -14069,6 +14247,7 @@ c_parser_expr_list (c_parser *parser, bool convert_p, bool fold_p,
if (orig_types)
*p_orig_types = orig_types;
c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
return ret;
}
@@ -16244,6 +16423,8 @@ c_parser_omp_clause_name (c_parser *parser)
result = PRAGMA_OMP_CLAUSE_USE_DEVICE_ADDR;
else if (!strcmp ("use_device_ptr", p))
result = PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR;
+ else if (!strcmp ("uses_allocators", p))
+ result = PRAGMA_OMP_CLAUSE_USES_ALLOCATORS;
break;
case 'v':
if (!strcmp ("vector", p))
@@ -16319,6 +16500,24 @@ c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list)
return list;
}
+/* Return, as an INTEGER_CST node, the number of elements for TYPE
+ (which is an ARRAY_TYPE). This one is a recursive count of all
+ ARRAY_TYPEs that are clumped together. (From cp/tree.cc). */
+
+static tree
+c_array_type_nelts_total (tree type)
+{
+ tree sz = array_type_nelts_top (type);
+ type = TREE_TYPE (type);
+ while (TREE_CODE (type) == ARRAY_TYPE)
+ {
+ tree n = array_type_nelts_top (type);
+ sz = fold_build2_loc (input_location, MULT_EXPR, sizetype, sz, n);
+ type = TREE_TYPE (type);
+ }
+ return sz;
+}
+
/* OpenACC 2.0, OpenMP 2.5:
variable-list:
identifier
@@ -16332,22 +16531,23 @@ c_parser_oacc_wait_list (c_parser *parser, location_t clause_loc, tree list)
in TREE_PURPOSE and the location in TREE_VALUE (accessible using
EXPR_LOCATION); return the list created.
- The optional ALLOW_DEREF argument is true if list items can use the deref
+ The optional MAP_LVALUE argument is true if list items can use the deref
(->) operator. */
struct omp_dim
{
- tree low_bound, length;
+ tree low_bound, length, stride;
location_t loc;
bool no_colon;
- omp_dim (tree lb, tree len, location_t lo, bool nc)
- : low_bound (lb), length (len), loc (lo), no_colon (nc) {}
+ omp_dim (tree lb, tree len, tree str, location_t lo, bool nc)
+ : low_bound (lb), length (len), stride (str), loc (lo), no_colon (nc) {}
};
static tree
c_parser_omp_variable_list (c_parser *parser,
location_t clause_loc,
enum omp_clause_code kind, tree list,
+ enum c_omp_region_type ort = C_ORT_OMP,
bool map_lvalue = false)
{
auto_vec<omp_dim> dims;
@@ -16447,12 +16647,26 @@ c_parser_omp_variable_list (c_parser *parser,
{
location_t loc = c_parser_peek_token (parser)->location;
bool save_c_omp_array_section_p = c_omp_array_section_p;
+ bool save_c_omp_array_shaping_op_p = c_omp_array_shaping_op_p;
c_omp_array_section_p = true;
+ c_omp_array_shaping_op_p
+ = (kind == OMP_CLAUSE_TO
+ || kind == OMP_CLAUSE_FROM
+ || ort == C_ORT_OMP_DECLARE_MAPPER);
c_expr expr = c_parser_expr_no_commas (parser, NULL);
if (expr.value != error_mark_node)
mark_exp_read (expr.value);
c_omp_array_section_p = save_c_omp_array_section_p;
+ c_omp_array_shaping_op_p = save_c_omp_array_shaping_op_p;
tree decl = expr.value;
+ tree reshaped_to = NULL_TREE;
+
+ if (TREE_CODE (decl) == VIEW_CONVERT_EXPR
+ && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+ {
+ reshaped_to = TREE_TYPE (decl);
+ decl = TREE_OPERAND (decl, 0);
+ }
/* This code rewrites a parsed expression containing various tree
codes used to represent array accesses into a more uniform nest of
@@ -16465,41 +16679,143 @@ c_parser_omp_variable_list (c_parser *parser,
dims.truncate (0);
if (TREE_CODE (decl) == OMP_ARRAY_SECTION)
{
+ size_t sections = 0;
+ tree orig_decl = decl;
+ bool update_p = (kind == OMP_CLAUSE_TO
+ || kind == OMP_CLAUSE_FROM);
+ bool maybe_ptr_based_noncontig_update = false;
+
+ while (update_p
+ && !reshaped_to
+ && (TREE_CODE (decl) == OMP_ARRAY_SECTION
+ || TREE_CODE (decl) == ARRAY_REF
+ || TREE_CODE (decl) == COMPOUND_EXPR))
+ {
+ if (TREE_CODE (decl) == COMPOUND_EXPR)
+ decl = TREE_OPERAND (decl, 1);
+ else
+ {
+ if (TREE_CODE (decl) == OMP_ARRAY_SECTION)
+ maybe_ptr_based_noncontig_update = true;
+ decl = TREE_OPERAND (decl, 0);
+ sections++;
+ }
+ }
+
+ decl = orig_decl;
+
while (TREE_CODE (decl) == OMP_ARRAY_SECTION)
{
tree low_bound = TREE_OPERAND (decl, 1);
tree length = TREE_OPERAND (decl, 2);
- dims.safe_push (omp_dim (low_bound, length, loc, false));
+ tree stride = TREE_OPERAND (decl, 3);
+ dims.safe_push (omp_dim (low_bound, length, stride, loc,
+ false));
decl = TREE_OPERAND (decl, 0);
+ if (sections > 0)
+ sections--;
}
+ /* The handling of INDIRECT_REF here in the presence of
+ array-shaping operations is a little tricky. We need to
+ avoid treating a pointer dereference as a unit-sized array
+ section when we have an array shaping operation, because we
+ don't want an indirection to consume one of the user's
+ requested array dimensions. E.g. if we have a
+ double-indirect pointer like:
+
+ int **foopp;
+ #pragma omp target update from(([N][N]) (*foopp)[0:X][0:Y])
+
+ We don't want to interpret this as:
+
+ foopp[0:1][0:X][0:Y]
+
+ else the array shape [N][N] won't match. Also we can't match
+ the array sections right-to-left instead, else this:
+
+ #pragma omp target update from(([N][N]) (*foopp)[0:X])
+
+ would not copy the dimensions:
+
+ (*foopp)[0:X][0:N]
+
+ as required. So, avoid descending through INDIRECT_REFs if
+ we have an array-shaping op.
+
+ If we *don't* have an array-shaping op, but we have a
+ multiply-indirected pointer and an array section like this:
+
+ int ***fooppp;
+ #pragma omp target update from((**fooppp)[0:X:S]
+
+ also avoid descending through more indirections than we have
+ array sections, since the noncontiguous update processing code
+ won't understand them (and doesn't need to traverse them
+ anyway). */
+
while (TREE_CODE (decl) == ARRAY_REF
- || TREE_CODE (decl) == INDIRECT_REF
+ || (TREE_CODE (decl) == INDIRECT_REF
+ && !reshaped_to)
|| TREE_CODE (decl) == COMPOUND_EXPR)
{
+ if (maybe_ptr_based_noncontig_update && sections == 0)
+ break;
+
if (TREE_CODE (decl) == COMPOUND_EXPR)
{
decl = TREE_OPERAND (decl, 1);
STRIP_NOPS (decl);
}
- else if (TREE_CODE (decl) == INDIRECT_REF)
+ else if (TREE_CODE (decl) == INDIRECT_REF
+ && !reshaped_to)
{
dims.safe_push (omp_dim (integer_zero_node,
- integer_one_node, loc, true));
+ integer_one_node, NULL_TREE, loc,
+ true));
decl = TREE_OPERAND (decl, 0);
}
else /* ARRAY_REF. */
{
tree index = TREE_OPERAND (decl, 1);
- dims.safe_push (omp_dim (index, integer_one_node, loc,
- true));
+ dims.safe_push (omp_dim (index, integer_one_node,
+ NULL_TREE, loc, true));
decl = TREE_OPERAND (decl, 0);
+ if (sections > 0)
+ sections--;
+ }
+ }
+
+ if (reshaped_to)
+ {
+ unsigned reshaped_dims = 0;
+
+ for (tree t = reshaped_to;
+ TREE_CODE (t) == ARRAY_TYPE;
+ t = TREE_TYPE (t))
+ reshaped_dims++;
+
+ if (dims.length () > reshaped_dims)
+ {
+ error_at (loc, "too many array section specifiers "
+ "for %qT", reshaped_to);
+ decl = error_mark_node;
+ }
+ else
+ {
+ /* We have a pointer DECL whose target should be
+ interpreted as an array with particular dimensions,
+ not "the pointer itself". So, add an indirection
+ here. */
+ decl = build_indirect_ref (loc, decl, RO_UNARY_STAR);
+ decl = build1_loc (loc, VIEW_CONVERT_EXPR, reshaped_to,
+ decl);
}
}
for (int i = dims.length () - 1; i >= 0; i--)
decl = build_omp_array_section (loc, decl, dims[i].low_bound,
- dims[i].length);
+ dims[i].length, dims[i].stride);
}
else if (TREE_CODE (decl) == INDIRECT_REF)
{
@@ -16508,7 +16824,7 @@ c_parser_omp_variable_list (c_parser *parser,
STRIP_NOPS (decl);
decl = build_omp_array_section (loc, decl, integer_zero_node,
- integer_one_node);
+ integer_one_node, NULL_TREE);
}
else if (TREE_CODE (decl) == ARRAY_REF)
{
@@ -16517,7 +16833,16 @@ c_parser_omp_variable_list (c_parser *parser,
decl = TREE_OPERAND (decl, 0);
STRIP_NOPS (decl);
- decl = build_omp_array_section (loc, decl, idx, integer_one_node);
+ decl = build_omp_array_section (loc, decl, idx, integer_one_node,
+ NULL_TREE);
+ }
+ else if (reshaped_to)
+ {
+ /* We're copying the whole of a reshaped array, originally a
+ base pointer. Rewrite as an array section. */
+ tree elems = c_array_type_nelts_total (reshaped_to);
+ decl = build_omp_array_section (loc, decl, size_zero_node, elems,
+ NULL_TREE);
}
else if (TREE_CODE (decl) == NON_LVALUE_EXPR
|| CONVERT_EXPR_P (decl))
@@ -16670,7 +16995,8 @@ c_parser_omp_variable_list (c_parser *parser,
break;
}
- dims.safe_push (omp_dim (low_bound, length, loc, no_colon));
+ dims.safe_push (omp_dim (low_bound, length, NULL_TREE, loc,
+ no_colon));
}
if (t != error_mark_node)
@@ -16694,7 +17020,8 @@ c_parser_omp_variable_list (c_parser *parser,
for (unsigned i = 0; i < dims.length (); i++)
t = build_omp_array_section (clause_loc, t,
dims[i].low_bound,
- dims[i].length);
+ dims[i].length,
+ dims[i].stride);
}
if ((kind == OMP_CLAUSE_DEPEND || kind == OMP_CLAUSE_AFFINITY)
@@ -16754,12 +17081,14 @@ c_parser_omp_variable_list (c_parser *parser,
}
/* Similarly, but expect leading and trailing parenthesis. This is a very
- common case for OpenACC and OpenMP clauses. The optional ALLOW_DEREF
+ common case for OpenACC and OpenMP clauses. The optional MAP_LVALUE
argument is true if list items can use the deref (->) operator. */
static tree
c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
- tree list, bool map_lvalue = false)
+ tree list,
+ enum c_omp_region_type ort = C_ORT_OMP,
+ bool map_lvalue = false)
{
/* The clauses location. */
location_t loc = c_parser_peek_token (parser)->location;
@@ -16780,12 +17109,729 @@ c_parser_omp_var_list_parens (c_parser *parser, enum omp_clause_code kind,
matching_parens parens;
if (parens.require_open (parser))
{
- list = c_parser_omp_variable_list (parser, loc, kind, list, map_lvalue);
+ list = c_parser_omp_variable_list (parser, loc, kind, list, ort,
+ map_lvalue);
parens.skip_until_found_close (parser);
}
return list;
}
+/* Helper for c_parser_omp_parm_list and c_finish_omp_declare_variant.
+ Compare two OpenMP parameter-list-item numeric ranges with a relative bound.
+ Returns true if they always overlap for any value of omp_num_args,
+ returns false otherwise.
+
+ Literal bounds are never compared with each other here,
+ c_parser_omp_parm_list already handles that case.
+
+ In hindsight, this was never really worth doing. If there is ever a case
+ found that this function gets wrong the best course of action is probably
+ to just disable the section that causes a problem. This function only
+ serves to diagnose overlapping numeric ranges in variadic functions early,
+ gimplify.cc:modify_call_for_omp_dispatch will always catch these problems
+ when the numeric range is expanded even if this function misses any cases.
+
+ If I could go back in time, I would stop myself from writing this, but it's
+ already done now. It technically does serve its purpose of providing better
+ diagnostics for niche scenarios, so until it breaks, here it is. */
+
+static bool
+c_omp_numeric_ranges_always_overlap (tree first, tree second)
+{
+ gcc_assert (first && TREE_CODE (first) == TREE_LIST
+ && second && TREE_CODE (second) == TREE_LIST);
+
+ auto bound_is_relative = [] (tree bound) -> bool
+ {
+ gcc_assert (!TREE_PURPOSE (bound)
+ || TREE_PURPOSE (bound)
+ == get_identifier ("omp relative bound"));
+ /* NULL_TREE means literal, the only other possible value is
+ get_identifier ("omp relative bound"), I hate this design though. */
+ return TREE_PURPOSE (bound);
+ };
+
+ tree lb1 = TREE_PURPOSE (first);
+ tree ub1 = TREE_VALUE (first);
+ gcc_assert (lb1 && ub1);
+ const bool lb1_relative = bound_is_relative (lb1);
+ const bool ub1_relative = bound_is_relative (ub1);
+ const bool first_mixed = !(lb1_relative && ub1_relative);
+
+ tree lb2 = TREE_PURPOSE (second);
+ tree ub2 = TREE_VALUE (second);
+ gcc_assert (lb2 && ub2);
+ const bool lb2_relative = bound_is_relative (lb2);
+ const bool ub2_relative = bound_is_relative (ub2);
+ const bool second_mixed = !(lb2_relative && ub2_relative);
+
+ /* Both ranges must have a relative bound. */
+ gcc_assert ((lb1_relative || ub1_relative)
+ && (lb2_relative || ub2_relative));
+
+ /* Both fully relative. */
+ if (!first_mixed && !second_mixed)
+ {
+ /* (relative : relative), (relative : relative) */
+ wi::tree_to_widest_ref lb1_v = wi::to_widest (TREE_VALUE (lb1));
+ wi::tree_to_widest_ref ub1_v = wi::to_widest (TREE_VALUE (ub1));
+ wi::tree_to_widest_ref lb2_v = wi::to_widest (TREE_VALUE (lb2));
+ wi::tree_to_widest_ref ub2_v = wi::to_widest (TREE_VALUE (ub2));
+ /* We compare lower bound to upper bound including equality because
+ upper bounds are stored as one past the end of the range. */
+ return (lb1_v >= lb2_v && lb1_v < ub2_v)
+ || (ub1_v > lb2_v && ub1_v <= ub2_v);
+ }
+ else if (first_mixed && second_mixed)
+ {
+ /* Note that this is a comparison, not logical and/or. */
+ if (lb1_relative == lb2_relative)
+ {
+ /* FIRST SECOND
+ LB1 UB1 LB2 UB2
+ (literal : relative), (literal : relative)
+ (relative : literal), (relative : literal) */
+
+ /* Simply compare the relative bounds, if they match the two ranges
+ will always overlap.
+ There is some other static analysis that can be done, but it isn't
+ worth the time to implement. */
+ gcc_assert (ub1_relative == ub2_relative);
+ if (lb1_relative)
+ {
+ /* (relative : literal), (relative : literal) */
+ return wi::to_widest (TREE_VALUE (lb1))
+ == wi::to_widest (TREE_VALUE (lb2));
+ }
+ else
+ {
+ /* (literal : relative), (literal : relative) */
+ return wi::to_widest (TREE_VALUE (ub1))
+ == wi::to_widest (TREE_VALUE (ub2));
+ }
+ }
+ else
+ {
+ /* FIRST SECOND
+ LB1 UB1 LB2 UB2
+ (literal : relative), (relative : literal)
+ (relative : literal), (literal : relative) */
+ gcc_assert (lb1_relative != lb2_relative
+ && ub2_relative != ub2_relative
+ && (lb1_relative == ub2_relative
+ || lb2_relative == ub1_relative));
+ /* There is definitely more interesting static analysis that can
+ be done here but it would probably be a waste of time. */
+ tree relative_lb = lb1_relative ? lb1 : lb2;
+ tree relative_ub = ub1_relative ? ub1 : ub2;
+ return wi::to_widest (TREE_VALUE (relative_lb))
+ >= wi::to_widest (TREE_VALUE (relative_ub));
+ }
+ }
+ else
+ {
+ /* FIRST SECOND
+ LB1 UB1 LB2 UB2
+ (literal : relative), (relative : relative)
+ (relative : relative), (literal : relative)
+
+ (relative : relative), (relative : literal)
+ (relative : literal), (relative : relative) */
+ gcc_assert ((first_mixed && !second_mixed)
+ || (!first_mixed && second_mixed));
+ tree lb_mixed = first_mixed ? lb1 : lb2;
+ tree ub_mixed = first_mixed ? ub1 : ub2;
+
+ tree lb_full_relative = !first_mixed ? lb1 : lb2;
+ tree ub_full_relative = !first_mixed ? ub1 : ub2;
+
+ if (bound_is_relative (lb_mixed))
+ {
+ return wi::to_widest (TREE_VALUE (lb_mixed))
+ >= wi::to_widest (TREE_VALUE (lb_full_relative))
+ && wi::to_widest (TREE_VALUE (lb_mixed))
+ < wi::to_widest (TREE_VALUE (ub_full_relative));
+ }
+ else
+ {
+ gcc_assert (bound_is_relative (ub_mixed));
+ return wi::to_widest (TREE_VALUE (ub_mixed))
+ > wi::to_widest (TREE_VALUE (lb_full_relative))
+ && wi::to_widest (TREE_VALUE (ub_mixed))
+ <= wi::to_widest (TREE_VALUE (ub_full_relative));
+ }
+ }
+ gcc_unreachable ();
+}
+
+
+/* Parse an OpenMP parameter-list.
+ parameter-list:
+ parameter-list-item[, parameter-list-item [, ...]]
+
+ parameter-list-item:
+ named parameter list item
+ parameter index (1 based)
+ numeric-range
+
+
+ numeric-range:
+ [bound]:[bound]
+
+ bound:
+ index-expr
+ omp_num_args[±logical_offset]
+
+ A named parameter list item is the name of a parameter. A parameter index
+ is a positive integer literal that is the 1 based index of a parameter.
+ A numeric-range is a pair of bounds of the form lb:ub, the values of each
+ bound form a closed interval of parameter indices. Bounds can be literal or
+ relative. An index-expr is a non-negative integer constant-expression that
+ is the value of a literal bound. The special identifier omp_num_args is
+ equal to the number of arguments passed to the function at the call site,
+ including the number of varargs. Optionally, a plus or minus with a
+ logical_offset may follow omp_num_args, logical_offset is a non-negative
+ integer constant-expression. A bound formed with omp_num_args is a relative
+ bound. If a bound is omitted, a default value is used. The default value
+ of lb is as if 1 were specified, the default value of ub is as if
+ omp_num_args were specified.
+
+ Each parameter-list-item is stored in a TREE_LIST. The PURPOSE is for
+ general use and left NULL_TREE here, and the item is stored in the VALUE.
+ An item is a TREE_LIST, the PURPOSE is an expression with the location of
+ the list item, and the VALUE is a representation of the item.
+ Each parameter-list-item is stored in a TREE_LIST node VALUE. The PURPOSE
+ is unused, and the VALUE is the item-repr.
+
+ Node - PUPOSE: NULL_TREE
+ - VALUE: item-with-location
+ item-with-location - PURPOSE: expr-with-location
+ - VALUE: item-repr
+
+ An item-repr is a INTEGER_CST or a TREE_LIST. An INTEGER_CST is the 0 based
+ index of a specified parameter, derived from a named parameter list item or
+ a parameter index. A TREE_LIST is a numeric-range where its PURPOSE is a
+ TREE_LIST representing the lb, and its VALUE is a TREE_LIST representing the
+ ub.
+
+ item-repr
+ INTEGER_CST - parameter index (0 based)
+ TREE_LIST - PURPOSE: TREE_LIST (lb)
+ - VALUE: TREE_LIST (ub)
+
+ lb and ub are a TREE_LIST of the following form;
+ TREE_LIST - PURPOSE: relative bound marker (NULL_TREE if literal)
+ - VALUE: expr-value
+
+ In non-variadic functions numeric ranges are immediately expanded into
+ INTEGER_CST nodes corresponding to each index specified by the interval.
+
+ The expr-value is an INTEGER_CST node of type integer_type_node, the value
+ corresponding to the expr. The value of lb is adjusted to be 0 based, while
+ the value of ub is adjusted to be 0 based, and one past the end to support
+ empty ranges. In other words, lb is adjusted by -1, and ub remains the
+ same.
+
+ Parameters that are specified but are not defined, out of range indices and
+ duplicate specifications are diagnosed. Additionally, numeric ranges that
+ can be proven to always overlap for any value of omp_num_args even before
+ expansion are also diagnosed. This provides diagnostics that occur before
+ the function is used. In hindsight, I wish I didn't waste my time on that
+ last one.
+ If a diagnostic is issued for a list item, it is not appened to the list and
+ parsing continues. Returns NULL_TREE if no valid list items are parsed.
+
+ This function strictly handles a parameter-list, it does not parse clause
+ modifiers, or parenthesis other than in the expr of a numeric range. */
+
+static tree
+c_parser_omp_parm_list (c_parser *parser, tree decl, const int parm_count)
+{
+ /* TODO: C++ front end was enhanced a little, gotta make changes in here
+ to match it. */
+ tree list = NULL_TREE;
+ /* Even though an adjust_args clause on a non-variadic function with 0
+ parameters is silly, we should still probably handle it gracefully. */
+ const bool variadic_p = TYPE_ARG_TYPES (TREE_TYPE (decl)) != void_list_node
+ && parm_count == 0;
+ const int omp_num_args_value = parm_count;
+
+ auto unique_append_to_list = [&list, &variadic_p] (int idx, location_t loc)
+ {
+ gcc_assert (idx >= 0);
+ /* Keep track of the last chain to append to the list. */
+ tree *chain = &list;
+ for (tree node = list; node; node = TREE_CHAIN (node))
+ {
+ chain = &TREE_CHAIN (node);
+ tree item = TREE_VALUE (node);
+ /* Skip numeric range nodes, only valid for variadic functions. */
+ if (variadic_p && TREE_CODE (TREE_VALUE (item)) != INTEGER_CST)
+ /* Early exit. */;
+ else if (wi::to_widest (TREE_VALUE (item)) == idx)
+ /* Return the item for diagnostic purposes. */
+ return item;
+ }
+ gcc_assert (*chain == NULL_TREE);
+ /* Store the location in PURPOSE for use in diagnostics. */
+ tree item = build_tree_list (build_empty_stmt (loc),
+ build_int_cst (integer_type_node, idx));
+ /* Leave PURPOSE unused for use by the caller of
+ c_parser_omp_parm_list. */
+ *chain = build_tree_list (NULL_TREE, item);
+ return NULL_TREE;
+ };
+
+ auto tok_terminates_item_p = [] (c_token *tok)
+ {
+ return tok->type == CPP_COMMA
+ || tok->type == CPP_CLOSE_PAREN;
+ };
+ /* The first list item is (obviously) not preceded by a comma. */
+ goto first_element;
+ do
+ {
+ /* Consume the comma. */
+ c_parser_consume_token (parser);
+ first_element:
+ c_token *const tok = c_parser_peek_token (parser);
+
+ /* OpenMP 6.0 (162:29-34)
+ A parameter list item can be one of the following:
+ • A named parameter list item;
+ • The position of a parameter in a parameter specification specified
+ by a positive integer, where 1 represents the first parameter; or
+ • A parameter range specified by lb : ub where both lb and ub must
+ be an expression of integer OpenMP type with the constant property
+ and the positive property.
+
+ The spec does not support arbitrary expression outside of a numeric
+ range. In theory they could be supported as a parameter index, but
+ for now we do not support that case. */
+
+ /* If we don't see a comma or close paren this can't be a named parameter
+ list item or a parameter index, it can only be a numeric range.
+ As far as I can tell, there is no well-formed code that could break
+ this assumption. */
+ if (!tok_terminates_item_p (c_parser_peek_2nd_token (parser))
+ /* Or this edge case, there is a default lower bound. */
+ || tok->type == CPP_COLON)
+ /* Early exit, numeric range case handled below. */;
+ else if (tok->type == CPP_NAME
+ && tok->id_kind == C_ID_ID)
+ {
+ if (strcmp (IDENTIFIER_POINTER (tok->value), "omp_num_args") == 0)
+ {
+ error_at (tok->location, "%<omp_num_args%> may only be used at "
+ "the start of a numeric range bound");
+ c_parser_consume_token (parser);
+ continue;
+ }
+ tree parm_decl = lookup_name (tok->value);
+
+ if (parm_decl && TREE_CODE (parm_decl) == PARM_DECL)
+ {
+ tree parm = DECL_ARGUMENTS (decl);
+ /* We store indices in 0 based form internally. */
+ int idx = 0;
+ while (parm != parm_decl)
+ {
+ gcc_assert (parm != NULL_TREE && parm != void_list_node);
+ ++idx;
+ parm = DECL_CHAIN (parm);
+ }
+ if (tree dupe = unique_append_to_list (idx, tok->location))
+ {
+ error_at (tok->location,
+ "OpenMP parameter list items must specify a "
+ "unique parameter");
+ inform (EXPR_LOCATION (TREE_PURPOSE (dupe)),
+ "parameter previously specified here");
+ }
+ }
+ else
+ {
+ /* It feels like the only reasonable solution is to cook our own
+ solution for this, undeclared_variable doesn't give us what
+ we wan't for more than a few reasons. */
+ error_at (tok->location,
+ "%qs is not a function parameter",
+ IDENTIFIER_POINTER (tok->value));
+ /* FIXME: Something like this is a good idea. */
+ /* if (parm_decl && TREE_CONSTANT (parm_decl))
+ inform (tok->location,
+ "an expression is only allowed in a "
+ "numeric range"); */
+ /* Don't use undeclared_variable if we are parsing a decl
+ instead of a declaration, it breaks subsequent lookups in
+ later functions. */
+ }
+ c_parser_consume_token (parser);
+ continue;
+ }
+ else if (tok->type == CPP_NUMBER)
+ {
+ if (wi::to_widest (tok->value) <= 0)
+ error_at (tok->location, "parameter indices in an OpenMP "
+ "parameter list must be positive");
+ else if (wi::to_widest (tok->value) > INT_MAX)
+ error_at (tok->location, "parameter index is too big");
+ else
+ {
+ /* We store indices 0 based internally, OpenMP specifies
+ 1 based indices, modify it. */
+ const int idx = tree_to_shwi (tok->value) - 1;
+ if (!variadic_p && idx >= parm_count)
+ error_at (tok->location,
+ "parameter list item index is out of range");
+ else
+ {
+ if (tree dupe = unique_append_to_list (idx, tok->location))
+ {
+ error_at (tok->location,
+ "OpenMP parameter list items must specify a "
+ "unique parameter");
+ inform (EXPR_LOCATION (TREE_PURPOSE (dupe)),
+ "parameter previously specified here");
+ }
+ }
+ }
+ c_parser_consume_token (parser);
+ continue;
+ }
+ else
+ {
+ gcc_checking_assert (tok_terminates_item_p
+ (c_parser_peek_2nd_token (parser)));
+ error_at (tok->location, "expected parameter or integer");
+ c_parser_consume_token (parser);
+ continue;
+ }
+ /* We have a numeric range or something ill formed now, this can be
+ an arbitrary expression. */
+
+ /* Empty bounds are delimited differently for lower and upper bounds,
+ handle them before calling parse_bound. */
+ auto parse_bound = [&] ()
+ {
+ enum omp_num_args
+ {
+ num_args_none,
+ num_args_plus,
+ num_args_minus,
+ num_args_no_offset
+ };
+ /* (OpenMP 6.0, 162:35-37)
+ In both lb and ub, an expression using omp_num_args, that enables
+ identification of parameters relative to the last argument of the
+ call, can be used with the form:
+ omp_num_args [± logical_offset] */
+
+ const omp_num_args parsed_omp_num_args = [&] ()
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ if (tok->type == CPP_NAME
+ && tok->id_kind == C_ID_ID
+ && strcmp (IDENTIFIER_POINTER (tok->value), "omp_num_args")
+ == 0)
+ {
+ /* Consume omp_num_args. */
+ c_parser_consume_token (parser);
+ c_token *op_tok = c_parser_peek_token (parser);
+ if (op_tok->type == CPP_PLUS)
+ {
+ c_parser_consume_token (parser);
+ return num_args_plus;
+ }
+ else if (op_tok->type == CPP_MINUS)
+ {
+ c_parser_consume_token (parser);
+ return num_args_minus;
+ }
+ return num_args_no_offset;
+ }
+ else
+ return num_args_none;
+ } (); /* IILE. */
+
+ /* If there was omp_num_args but no operator an expr is not
+ permitted, we are finished with this bound. */
+ if (parsed_omp_num_args == num_args_no_offset)
+ return build_int_cst (integer_type_node, omp_num_args_value);
+ gcc_assert (parsed_omp_num_args < num_args_no_offset);
+
+ c_expr expr = c_parser_expr_no_commas (parser, NULL);
+ /* I don't know if this location is correct. */
+ const location_t expr_loc = expr.get_location ();
+ /* I don't think read_p true is correct. */
+ expr = convert_lvalue_to_rvalue (expr_loc, expr, false, true);
+ if (expr.value == error_mark_node)
+ return error_mark_node;
+ tree folded = c_fully_fold (expr.value, false, NULL);
+ if (!TREE_CONSTANT (folded))
+ {
+ error_at (expr_loc, "expression of a bound must be a "
+ "constant expression");
+ return error_mark_node;
+ }
+ /* This seems wrong... */
+ gcc_assert (TREE_CODE (folded) == INTEGER_CST);
+ /* If we have omp_num_args, expr can be 0,
+ if we don't, expr must be positive. */
+ const int sgn = tree_int_cst_sgn (folded);
+ /* I'm sure this is wrong but I dunno a better way right now. */
+ const ptrdiff_t value = tree_to_shwi (folded);
+ switch (parsed_omp_num_args)
+ {
+ case num_args_none:
+ {
+ if (sgn != 1)
+ {
+ error_at (expr_loc, "expression of bound must be "
+ "positive");
+ return error_mark_node;
+ }
+ if (!variadic_p && value > omp_num_args_value)
+ {
+ error_at (expr_loc, "expression of bound is out "
+ "of range");
+ return error_mark_node;
+ }
+ return build_int_cst (integer_type_node, value);
+ }
+ case num_args_plus:
+ {
+ if (sgn != 0)
+ {
+ error_at (expr_loc,
+ "logical offset must be equal to 0 in a bound "
+ "of the form %<omp_num_args+logical-offset%>");
+ return error_mark_node;
+ }
+ return build_int_cst (integer_type_node, omp_num_args_value);
+ }
+ case num_args_minus:
+ {
+ if (sgn == -1)
+ {
+ error_at (expr_loc,
+ "logical offset must be non-negative");
+ return error_mark_node;
+ }
+ if (variadic_p)
+ return build_int_cst (integer_type_node, -value);
+ const ptrdiff_t parm_index = omp_num_args_value - value;
+ if (parm_index <= 0)
+ {
+ error_at (expr_loc,
+ "bound with logical offset evaluates to an "
+ "out of range index");
+ return error_mark_node;
+ }
+ return build_int_cst (integer_type_node, parm_index);
+ }
+ case num_args_no_offset:
+ /* Handled above. */
+ default:
+ gcc_unreachable ();
+ }
+ gcc_unreachable ();
+ };
+ const location_t num_range_loc_begin = tok->location;
+
+ /* As stated above, empty bounds are handled here. */
+ tree lb = c_parser_next_token_is (parser, CPP_COLON) ? NULL_TREE
+ : parse_bound ();
+ /* I wish we could error here saying that we expect an unqualified-id,
+ an integer, or an expression. Parsing the expression emits the error
+ right away though. */
+ if (lb && error_operand_p (lb))
+ {
+ c_parser_skip_to_end_of_parameter (parser);
+ continue;
+ }
+ /* Tokens get consumed by parse_bound. */
+ if (c_parser_next_token_is_not (parser, CPP_COLON))
+ {
+ /* lower_bound can only be null if the next token was a colon. */
+ gcc_assert (lb != NULL_TREE);
+ c_parser_error (parser, "expected %<:%>");
+ if (tok_terminates_item_p (c_parser_peek_token (parser)))
+ {
+ const location_t loc = make_location (num_range_loc_begin,
+ num_range_loc_begin,
+ input_location);
+ inform (loc, "an expression is only allowed in a numeric range");
+ }
+ c_parser_skip_to_end_of_parameter (parser);
+ continue;
+ }
+ const location_t colon_loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_token (parser);
+
+ tree ub = tok_terminates_item_p (c_parser_peek_token (parser))
+ ? NULL_TREE : parse_bound ();
+ if (!ub || ub == error_mark_node)
+ c_parser_skip_to_end_of_parameter (parser);
+
+ location_t num_range_loc_end = ub != NULL_TREE ? input_location
+ : colon_loc;
+ location_t num_range_loc = make_location (num_range_loc_begin,
+ num_range_loc_begin,
+ num_range_loc_end);
+ /* I think we are supposed to have some sort of diagnostic here, I'm just
+ not sure what it should be. */
+ if (lb == error_mark_node || ub == error_mark_node)
+ continue;
+ /* Handle default bounds. */
+ const ptrdiff_t lb_val = lb ? tree_to_shwi (lb)
+ : 1;
+ const ptrdiff_t ub_val = ub ? tree_to_shwi (ub)
+ : omp_num_args_value;
+
+ gcc_assert (variadic_p || (lb_val > 0 && ub_val > 0));
+ /* We only know this at this point if they are both negative/zero or both
+ positive, so basically if both or neither use omp_num_args. */
+ /* FIXME: need a test for this case, I think we are missing this case
+ in the C++ front end, so add it. */
+ if (((lb_val <= 0) == (ub_val <= 0)) && lb_val > ub_val)
+ {
+ error_at (num_range_loc,
+ "numeric range lower bound must be less than "
+ "or equal to upper bound");
+ continue;
+ }
+
+ auto add_range_known = [&] (const int lb, const int ub)
+ {
+ gcc_assert (lb > 0 && ub > 0 && lb <= ub);
+
+ for (int idx = lb; idx <= ub; ++idx)
+ {
+ gcc_assert (variadic_p || idx <= parm_count);
+ if (tree dupe = unique_append_to_list (idx - 1, num_range_loc))
+ {
+ error_at (num_range_loc,
+ "expansion of numeric range specifies "
+ "non-unique index %d", idx);
+ inform (EXPR_LOCATION (TREE_PURPOSE (dupe)),
+ "parameter previously specified here");
+ }
+ }
+ };
+ /* Store ub as exclusive (one past the end) so we can differentiate an
+ empty range from a range of one index without ever encoding lb as
+ greater than ub.
+ Semantically, OpenMP does not allow this as numeric range bounds are
+ specified to be inclusive, but we utilize it for diagnostic purposes.
+ This is explained in detail below. */
+ auto add_range_unknown = [&] (const int lb_in,
+ const bool lb_relative_p,
+ const int ub_in,
+ const bool ub_relative_p)
+ {
+ /* If both bounds are relative, then lb should be <= ub. */
+ gcc_assert ((!(lb_relative_p && ub_relative_p) || lb_in <= ub_in)
+ /* We only deal with ranges that aren't known here, so
+ at least one bound should be relative to num args. */
+ && (lb_relative_p || ub_relative_p));
+ /* Adjust to be 0 based, -1 now corresponds to the last arg. */
+ const int lb = lb_in - 1;
+ /* Adjust to be 0 based, but add 1 to make it one past the end. */
+ const int ub = ub_in - 1 + 1;
+ /* We don't check against the non-range indices, we already check
+ that by adding any indices we can be sure of WAY below. */
+ auto build_bound = [] (int val, bool add_num_args)
+ {
+ return build_tree_list (add_num_args
+ ? get_identifier ("omp relative bound")
+ : NULL_TREE,
+ build_int_cst (integer_type_node, val));
+ };
+ tree lb_node = build_bound (lb, lb_relative_p);
+ tree ub_node = build_bound (ub, ub_relative_p);
+ tree new_range = build_tree_list (lb_node, ub_node);
+ /* Keep track of the last chain to append to the list. */
+ tree *chain = &list;
+ for (tree node = list; node; node = TREE_CHAIN (node))
+ {
+ chain = &TREE_CHAIN (node);
+ tree item = TREE_VALUE (node);
+ gcc_assert (TREE_PURPOSE (item));
+ if (TREE_CODE (TREE_VALUE (item)) == INTEGER_CST)
+ continue;
+
+ tree range = TREE_VALUE (item);
+ if (c_omp_numeric_ranges_always_overlap (range, new_range))
+ {
+ error_at (num_range_loc,
+ "numeric range always overlaps with another "
+ "range");
+ inform (EXPR_LOCATION (TREE_PURPOSE (item)),
+ "overlaps with this range");
+ /* Do not add this range. */
+ return;
+ }
+ }
+ tree item = build_tree_list (build_empty_stmt (num_range_loc),
+ new_range);
+ /* Leave PURPOSE unused for use by the caller of
+ c_parser_omp_parm_list. */
+ *chain = build_tree_list (NULL_TREE, item);
+ };
+
+ if (lb_val > 0 && ub_val > 0)
+ {
+ gcc_assert (variadic_p
+ || (lb_val <= parm_count && ub_val <= parm_count));
+ add_range_known (lb_val, ub_val);
+ }
+ else if (lb_val <= 0 && ub_val <= 0)
+ {
+ gcc_assert (variadic_p);
+ add_range_unknown (lb_val, true, ub_val, true);
+ }
+ /* Add the indices that will be specified for all well-formed calls to
+ the function. This lets us diagnose indices that were specified
+ (or rather, will be when the numeric range is expanded) multiple times
+ before the function is even called. We must adjust the literal bound
+ of the numeric range accordingly depending on how many indices we
+ add to prevent them from being specified again erroneously once the
+ range is expanded at the call site.
+ We can do this because we support expansion of unknown ranges
+ evaluating to an empty interval, as mentioned above in
+ add_range_unknown. */
+ else if (lb_val > 0)
+ {
+ gcc_assert (variadic_p);
+ /* FIXME: Make sure to add a test where lb > parm_count, that
+ originally could break this realized that would break this
+ optimization. */
+ /* In the case that UB refers to the last argument, we can assume all
+ non-variadic arguments between LB and the last non-variadic arg,
+ if any, will always be specified. */
+ const int known_upper_bound = ub_val == 0 && lb_val <= parm_count
+ ? parm_count : lb_val;
+ add_range_known (lb_val, known_upper_bound);
+ add_range_unknown (known_upper_bound + 1, false, ub_val, true);
+ }
+ else if (ub_val > 0)
+ {
+ gcc_assert (variadic_p);
+ /* We can do this because numeric ranges are inclusive, any
+ well-formed call to this function will cause the range to evaluate
+ to include the literal index. */
+ add_range_known (ub_val, ub_val);
+ add_range_unknown (lb_val, true, ub_val - 1, false);
+ }
+ else
+ gcc_unreachable ();
+
+ } while (c_parser_next_token_is (parser, CPP_COMMA));
+ return list;
+}
+
+
/* OpenACC 2.0:
copy ( variable-list )
copyin ( variable-list )
@@ -16875,7 +17921,7 @@ c_parser_oacc_data_clause (c_parser *parser, pragma_omp_clause c_kind,
}
}
nl = c_parser_omp_variable_list (parser, open_loc, OMP_CLAUSE_MAP, list,
- false);
+ C_ORT_ACC, false);
parens.skip_until_found_close (parser);
}
@@ -16900,7 +17946,8 @@ c_parser_oacc_data_clause_deviceptr (c_parser *parser, tree list)
/* Can't use OMP_CLAUSE_MAP here (that is, can't use the generic
c_parser_oacc_data_clause), as for PRAGMA_OACC_CLAUSE_DEVICEPTR,
variable-list must only allow for pointer variables. */
- vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL);
+ vars = c_parser_omp_var_list_parens (parser, OMP_CLAUSE_ERROR, NULL,
+ C_ORT_ACC);
for (t = vars; t && t; t = TREE_CHAIN (t))
{
tree v = TREE_PURPOSE (t);
@@ -18459,7 +19506,7 @@ c_parser_omp_clause_private (c_parser *parser, tree list)
static tree
c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind,
- bool is_omp, tree list)
+ enum c_omp_region_type ort, tree list)
{
location_t clause_loc = c_parser_peek_token (parser)->location;
matching_parens parens;
@@ -18470,7 +19517,7 @@ c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind,
enum tree_code code = ERROR_MARK;
tree reduc_id = NULL_TREE;
- if (kind == OMP_CLAUSE_REDUCTION && is_omp)
+ if (kind == OMP_CLAUSE_REDUCTION && ort == C_ORT_OMP)
{
if (c_parser_next_token_is_keyword (parser, RID_DEFAULT)
&& c_parser_peek_2nd_token (parser)->type == CPP_COMMA)
@@ -18535,13 +19582,21 @@ c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind,
code = MAX_EXPR;
break;
}
+ if (ort == C_ORT_ACC)
+ goto name_error;
reduc_id = c_parser_peek_token (parser)->value;
break;
}
default:
- c_parser_error (parser,
- "expected %<+%>, %<*%>, %<-%>, %<&%>, "
- "%<^%>, %<|%>, %<&&%>, %<||%> or identifier");
+ name_error:
+ if (ort == C_ORT_OMP)
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%> or identifier");
+ else
+ c_parser_error (parser,
+ "expected %<+%>, %<*%>, %<-%>, %<&%>, "
+ "%<^%>, %<|%>, %<&&%>, %<||%>, %<min%> or %<max%>");
c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, 0);
return list;
}
@@ -18551,9 +19606,15 @@ c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind,
{
tree nl, c;
- nl = c_parser_omp_variable_list (parser, clause_loc, kind, list);
+ nl = c_parser_omp_variable_list (parser, clause_loc, kind, list, ort);
+
for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
{
+ OMP_CLAUSE_REDUCTION_CODE (c) = code;
+ /* OpenACC does not require anything below. */
+ if (ort == C_ORT_ACC)
+ continue;
+
tree d = OMP_CLAUSE_DECL (c), type;
if (TREE_CODE (d) != OMP_ARRAY_SECTION)
type = TREE_TYPE (d);
@@ -18577,7 +19638,6 @@ c_parser_omp_clause_reduction (c_parser *parser, enum omp_clause_code kind,
}
while (TREE_CODE (type) == ARRAY_TYPE)
type = TREE_TYPE (type);
- OMP_CLAUSE_REDUCTION_CODE (c) = code;
if (task)
OMP_CLAUSE_REDUCTION_TASK (c) = 1;
else if (inscan)
@@ -19212,6 +20272,213 @@ c_parser_omp_clause_allocate (c_parser *parser, tree list)
return nl;
}
+/* OpenMP 5.0:
+ uses_allocators ( allocator-list )
+
+ allocator-list:
+ allocator
+ allocator , allocator-list
+ allocator ( traits-array )
+ allocator ( traits-array ) , allocator-list
+
+ OpenMP 5.2:
+
+ uses_allocators ( modifier : allocator-list )
+ uses_allocators ( modifier , modifier : allocator-list )
+
+ modifier:
+ traits ( traits-array )
+ memspace ( mem-space-handle ) */
+
+static tree
+c_parser_omp_clause_uses_allocators (c_parser *parser, tree list)
+{
+ location_t clause_loc = c_parser_peek_token (parser)->location;
+ tree t = NULL_TREE, nl = list;
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ tree memspace_expr = NULL_TREE;
+ tree traits_var = NULL_TREE;
+
+ struct item_tok
+ {
+ location_t loc;
+ tree id;
+ item_tok (void) : loc (UNKNOWN_LOCATION), id (NULL_TREE) {}
+ };
+ struct item { item_tok name, arg; };
+ auto_vec<item> *modifiers = NULL, *allocators = NULL;
+ auto_vec<item> *cur_list = new auto_vec<item> (4);
+
+ while (true)
+ {
+ item it;
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ it.name.id = tok->value;
+ it.name.loc = tok->location;
+ c_parser_consume_token (parser);
+
+ if (c_parser_next_token_is (parser, CPP_OPEN_PAREN))
+ {
+ matching_parens parens2;
+ parens2.consume_open (parser);
+
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tok = c_parser_peek_token (parser);
+ it.arg.id = tok->value;
+ it.arg.loc = tok->location;
+ c_parser_consume_token (parser);
+ }
+ else
+ {
+ c_parser_error (parser, "expected identifier");
+ parens2.skip_until_found_close (parser);
+ goto end;
+ }
+ parens2.skip_until_found_close (parser);
+ }
+ }
+
+ cur_list->safe_push (it);
+
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ c_parser_consume_token (parser);
+ else if (c_parser_next_token_is (parser, CPP_COLON))
+ {
+ if (modifiers)
+ {
+ c_parser_error (parser, "expected %<)%>");
+ goto end;
+ }
+ else
+ {
+ c_parser_consume_token (parser);
+ modifiers = cur_list;
+ cur_list = new auto_vec<item> (4);
+ }
+ }
+ else if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ {
+ gcc_assert (allocators == NULL);
+ allocators = cur_list;
+ cur_list = NULL;
+ break;
+ }
+ else
+ {
+ c_parser_error (parser, "expected %<)%>");
+ goto end;
+ }
+ }
+
+ if (modifiers)
+ for (unsigned i = 0; i < modifiers->length (); i++)
+ {
+ item& it = (*modifiers)[i];
+ const char *p = IDENTIFIER_POINTER (it.name.id);
+ int strcmp_traits = 1, strcmp_memspace = 1;
+
+ if ((strcmp_traits = strcmp ("traits", p)) == 0
+ || (strcmp_memspace = strcmp ("memspace", p)) == 0)
+ {
+ if ((strcmp_traits == 0 && traits_var != NULL_TREE)
+ || (strcmp_memspace == 0 && memspace_expr != NULL_TREE))
+ {
+ error_at (it.name.loc, "duplicate %qs modifier", p);
+ goto end;
+ }
+ t = lookup_name (it.arg.id);
+ if (t == NULL_TREE)
+ {
+ undeclared_variable (it.arg.loc, it.arg.id);
+ t = error_mark_node;
+ }
+ else if (strcmp_memspace == 0)
+ memspace_expr = t;
+ else if (strcmp_traits == 0)
+ traits_var = t;
+ else
+ gcc_unreachable ();
+ }
+ else
+ {
+ error_at (it.name.loc, "unknown modifier %qE", it.name.id);
+ goto end;
+ }
+ }
+
+ if (allocators)
+ {
+ if (modifiers)
+ {
+ if (allocators->length () > 1)
+ {
+ error_at ((*allocators)[1].name.loc,
+ "%<uses_allocators%> clause only accepts a single "
+ "allocator when using modifiers");
+ goto end;
+ }
+ else if ((*allocators)[0].arg.id)
+ {
+ error_at ((*allocators)[0].arg.loc,
+ "legacy %<%E(%E)%> traits syntax not allowed in "
+ "%<uses_allocators%> clause when using modifiers",
+ (*allocators)[0].name.id, (*allocators)[0].arg.id);
+ goto end;
+ }
+ }
+
+ for (unsigned i = 0; i < allocators->length (); i++)
+ {
+ item& it = (*allocators)[i];
+ t = lookup_name (it.name.id);
+ if (t == NULL_TREE)
+ {
+ undeclared_variable (it.name.loc, it.name.id);
+ goto end;
+ }
+ else if (t != error_mark_node)
+ {
+ tree t2 = NULL_TREE;
+ if (it.arg.id)
+ {
+ t2 = lookup_name (it.arg.id);
+ if (t2 == NULL_TREE)
+ {
+ undeclared_variable (it.arg.loc, it.arg.id);
+ goto end;
+ }
+ }
+ else
+ t2 = traits_var;
+
+ tree c = build_omp_clause (clause_loc,
+ OMP_CLAUSE_USES_ALLOCATORS);
+ OMP_CLAUSE_USES_ALLOCATORS_ALLOCATOR (c) = t;
+ OMP_CLAUSE_USES_ALLOCATORS_MEMSPACE (c) = memspace_expr;
+ OMP_CLAUSE_USES_ALLOCATORS_TRAITS (c) = t2;
+ OMP_CLAUSE_CHAIN (c) = nl;
+ nl = c;
+ }
+ }
+ }
+ end:
+ if (cur_list)
+ delete cur_list;
+ if (modifiers)
+ delete modifiers;
+ if (allocators)
+ delete allocators;
+ parens.skip_until_found_close (parser);
+ return nl;
+}
+
/* OpenMP 4.0:
linear ( variable-list )
linear ( variable-list : expression )
@@ -19651,10 +20918,10 @@ c_parser_omp_iterators (c_parser *parser)
pushdecl (iter_var);
*last = make_tree_vec (6);
- TREE_VEC_ELT (*last, 0) = iter_var;
- TREE_VEC_ELT (*last, 1) = begin;
- TREE_VEC_ELT (*last, 2) = end;
- TREE_VEC_ELT (*last, 3) = step;
+ OMP_ITERATORS_VAR (*last) = iter_var;
+ OMP_ITERATORS_BEGIN (*last) = begin;
+ OMP_ITERATORS_END (*last) = end;
+ OMP_ITERATORS_STEP (*last) = step;
last = &TREE_CHAIN (*last);
if (c_parser_next_token_is (parser, CPP_COMMA))
@@ -19719,7 +20986,7 @@ c_parser_omp_clause_affinity (c_parser *parser, tree list)
tree block = pop_scope ();
if (iterators != error_mark_node)
{
- TREE_VEC_ELT (iterators, 5) = block;
+ OMP_ITERATORS_BLOCK (iterators) = block;
for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
OMP_CLAUSE_DECL (c) = build_tree_list (iterators,
OMP_CLAUSE_DECL (c));
@@ -19836,7 +21103,7 @@ c_parser_omp_clause_depend (c_parser *parser, tree list)
if (iterators == error_mark_node)
iterators = NULL_TREE;
else
- TREE_VEC_ELT (iterators, 5) = block;
+ OMP_ITERATORS_BLOCK (iterators) = block;
}
for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
@@ -19936,13 +21203,12 @@ c_parser_omp_clause_doacross (c_parser *parser, tree list)
map ( [map-type-modifier[,] ...] map-kind: variable-list )
map-type-modifier:
- always | close */
+ always | close | present | iterator (iterators-definition) */
static tree
-c_parser_omp_clause_map (c_parser *parser, tree list)
+c_parser_omp_clause_map (c_parser *parser, tree list, enum gomp_map_kind kind)
{
location_t clause_loc = c_parser_peek_token (parser)->location;
- enum gomp_map_kind kind = GOMP_MAP_TOFROM;
tree nl, c;
matching_parens parens;
@@ -19951,22 +21217,57 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
int pos = 1;
int map_kind_pos = 0;
- while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME)
+ int iterator_length = 0;
+ for (;;)
{
- if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COLON)
+ c_token *tok = c_parser_peek_nth_token_raw (parser, pos);
+ if (tok->type != CPP_NAME)
+ break;
+
+ const char *p = IDENTIFIER_POINTER (tok->value);
+ c_token *next_tok = c_parser_peek_nth_token_raw (parser, pos + 1);
+ if (strcmp (p, "iterator") == 0 && next_tok->type == CPP_OPEN_PAREN)
+ {
+ unsigned n = pos + 2;
+ if (c_parser_check_balanced_raw_token_sequence (parser, &n)
+ && c_parser_peek_nth_token_raw (parser, n)->type
+ == CPP_CLOSE_PAREN)
+ {
+ iterator_length = n - pos + 1;
+ pos = n;
+ next_tok = c_parser_peek_nth_token_raw (parser, pos + 1);
+ }
+ }
+
+ if (next_tok->type == CPP_COLON)
{
map_kind_pos = pos;
break;
}
- if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA)
+ if (next_tok->type == CPP_COMMA)
pos++;
+ else if (c_parser_peek_nth_token_raw (parser, pos + 1)->type
+ == CPP_OPEN_PAREN)
+ {
+ unsigned int npos = pos + 2;
+ if (c_parser_check_balanced_raw_token_sequence (parser, &npos)
+ && (c_parser_peek_nth_token_raw (parser, npos)->type
+ == CPP_CLOSE_PAREN)
+ && (c_parser_peek_nth_token_raw (parser, npos + 1)->type
+ == CPP_COMMA))
+ pos = npos + 1;
+ }
+
pos++;
}
int always_modifier = 0;
int close_modifier = 0;
int present_modifier = 0;
+ int mapper_modifier = 0;
+ tree mapper_name = NULL_TREE;
+ tree iterators = NULL_TREE;
for (int pos = 1; pos < map_kind_pos; ++pos)
{
c_token *tok = c_parser_peek_token (parser);
@@ -19987,6 +21288,7 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
return list;
}
always_modifier++;
+ c_parser_consume_token (parser);
}
else if (strcmp ("close", p) == 0)
{
@@ -19997,6 +21299,60 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
return list;
}
close_modifier++;
+ c_parser_consume_token (parser);
+ }
+ else if (strcmp ("mapper", p) == 0)
+ {
+ c_parser_consume_token (parser);
+
+ matching_parens mparens;
+ if (mparens.require_open (parser))
+ {
+ if (mapper_modifier)
+ {
+ c_parser_error (parser, "too many %<mapper%> modifiers");
+ /* Assume it's a well-formed mapper modifier, even if it
+ seems to be in the wrong place. */
+ c_parser_consume_token (parser);
+ mparens.require_close (parser);
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+
+ tok = c_parser_peek_token (parser);
+
+ switch (tok->type)
+ {
+ case CPP_NAME:
+ {
+ mapper_name = tok->value;
+ c_parser_consume_token (parser);
+ }
+ break;
+
+ case CPP_KEYWORD:
+ if (tok->keyword == RID_DEFAULT)
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+ /* Fallthrough. */
+
+ default:
+ error_at (tok->location,
+ "expected identifier or %<default%>");
+ return list;
+ }
+
+ if (!mparens.require_close (parser))
+ {
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+
+ mapper_modifier++;
+ pos += 3;
+ }
}
else if (strcmp ("present", p) == 0)
{
@@ -20007,16 +21363,29 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
return list;
}
present_modifier++;
+ c_parser_consume_token (parser);
+ }
+ else if (strcmp ("iterator", p) == 0
+ && c_parser_peek_2nd_token (parser)->type == CPP_OPEN_PAREN)
+ {
+ if (iterators)
+ {
+ c_parser_error (parser, "too many %<iterator%> modifiers");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ iterators = c_parser_omp_iterators (parser);
+ pos += iterator_length - 1;
+ continue;
}
else
{
c_parser_error (parser, "%<map%> clause with map-type modifier other "
- "than %<always%>, %<close%> or %<present%>");
+ "than %<always%>, %<close%>, %<iterator%>, "
+ "%<mapper%> or %<present%>");
parens.skip_until_found_close (parser);
return list;
}
-
- c_parser_consume_token (parser);
}
if (c_parser_next_token_is (parser, CPP_NAME)
@@ -20058,10 +21427,48 @@ c_parser_omp_clause_map (c_parser *parser, tree list)
}
nl = c_parser_omp_variable_list (parser, clause_loc, OMP_CLAUSE_MAP, list,
- true);
+ (kind == GOMP_MAP_UNSET
+ ? C_ORT_OMP_DECLARE_MAPPER
+ : C_ORT_OMP), true);
+
+ tree last_new = NULL_TREE;
+
+ if (iterators)
+ {
+ tree block = pop_scope ();
+ if (iterators == error_mark_node)
+ iterators = NULL_TREE;
+ else
+ OMP_ITERATORS_BLOCK (iterators) = block;
+ }
for (c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
- OMP_CLAUSE_SET_MAP_KIND (c, kind);
+ {
+ OMP_CLAUSE_SET_MAP_KIND (c, kind);
+ OMP_CLAUSE_ITERATORS (c) = iterators;
+ last_new = c;
+ }
+
+ if (mapper_name)
+ {
+ tree name = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_PUSH_MAPPER_NAME);
+ OMP_CLAUSE_DECL (name) = mapper_name;
+ if (iterators)
+ OMP_CLAUSE_ITERATORS (name) = iterators;
+ OMP_CLAUSE_CHAIN (name) = nl;
+ nl = name;
+
+ gcc_assert (last_new);
+
+ name = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_POP_MAPPER_NAME);
+ OMP_CLAUSE_DECL (name) = null_pointer_node;
+ if (iterators)
+ OMP_CLAUSE_ITERATORS (name) = iterators;
+ OMP_CLAUSE_CHAIN (name) = OMP_CLAUSE_CHAIN (last_new);
+ OMP_CLAUSE_CHAIN (last_new) = name;
+ }
parens.skip_until_found_close (parser);
return nl;
@@ -20301,8 +21708,11 @@ c_parser_omp_clause_device_type (c_parser *parser, tree list)
to ( variable-list )
OpenMP 5.1:
- from ( [present :] variable-list )
- to ( [present :] variable-list ) */
+ from ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list )
+ to ( [motion-modifier[,] [motion-modifier[,]...]:] variable-list )
+
+ motion-modifier:
+ present | iterator (iterators-definition) */
static tree
c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind,
@@ -20313,25 +21723,179 @@ c_parser_omp_clause_from_to (c_parser *parser, enum omp_clause_code kind,
if (!parens.require_open (parser))
return list;
- bool present = false;
- c_token *token = c_parser_peek_token (parser);
+ int pos = 1, colon_pos = 0;
+ int iterator_length = 0;
- if (token->type == CPP_NAME
- && strcmp (IDENTIFIER_POINTER (token->value), "present") == 0
- && c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ while (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_NAME)
{
- present = true;
- c_parser_consume_token (parser);
- c_parser_consume_token (parser);
+ const char *identifier =
+ IDENTIFIER_POINTER (c_parser_peek_nth_token_raw (parser, pos)->value);
+ if (c_parser_peek_nth_token_raw (parser, pos + 1)->type
+ == CPP_OPEN_PAREN)
+ {
+ unsigned int npos = pos + 2;
+ if (c_parser_check_balanced_raw_token_sequence (parser, &npos)
+ && (c_parser_peek_nth_token_raw (parser, npos)->type
+ == CPP_CLOSE_PAREN))
+ {
+ if (strcmp (identifier, "iterator") == 0)
+ iterator_length = npos - pos + 1;
+ pos = npos;
+ }
+ }
+ if (c_parser_peek_nth_token_raw (parser, pos + 1)->type == CPP_COMMA)
+ pos += 2;
+ else
+ pos++;
+ if (c_parser_peek_nth_token_raw (parser, pos)->type == CPP_COLON)
+ {
+ colon_pos = pos;
+ break;
+ }
+ }
+
+ int present_modifier = false;
+ int mapper_modifier = false;
+ tree mapper_name = NULL_TREE;
+ tree iterators = NULL_TREE;
+
+ for (int pos = 1; pos < colon_pos; ++pos)
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ if (tok->type == CPP_COMMA)
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ const char *p = IDENTIFIER_POINTER (tok->value);
+ if (strcmp ("present", p) == 0)
+ {
+ if (present_modifier)
+ {
+ c_parser_error (parser, "too many %<present%> modifiers");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ present_modifier++;
+ c_parser_consume_token (parser);
+ }
+ else if (strcmp ("iterator", p) == 0)
+ {
+ if (iterators)
+ {
+ c_parser_error (parser, "too many %<iterator%> modifiers");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ iterators = c_parser_omp_iterators (parser);
+ pos += iterator_length - 1;
+ }
+ else if (strcmp ("mapper", p) == 0)
+ {
+ c_parser_consume_token (parser);
+
+ matching_parens mparens;
+ if (mparens.require_open (parser))
+ {
+ if (mapper_modifier)
+ {
+ c_parser_error (parser, "too many %<mapper%> modifiers");
+ /* Assume it's a well-formed mapper modifier, even if it
+ seems to be in the wrong place. */
+ c_parser_consume_token (parser);
+ mparens.require_close (parser);
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+
+ tok = c_parser_peek_token (parser);
+
+ switch (tok->type)
+ {
+ case CPP_NAME:
+ {
+ mapper_name = tok->value;
+ c_parser_consume_token (parser);
+ }
+ break;
+
+ case CPP_KEYWORD:
+ if (tok->keyword == RID_DEFAULT)
+ {
+ c_parser_consume_token (parser);
+ break;
+ }
+ /* Fallthrough. */
+
+ default:
+ error_at (tok->location,
+ "expected identifier or %<default%>");
+ return list;
+ }
+
+ if (!mparens.require_close (parser))
+ {
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+
+ mapper_modifier++;
+ pos += 3;
+ }
+ }
+ else
+ {
+ c_parser_error (parser, "%<to%> or %<from%> clause with modifier "
+ "other than %<iterator%>, %<mapper%> or %<present%>");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
}
- tree nl = c_parser_omp_variable_list (parser, loc, kind, list);
+ if (colon_pos)
+ c_parser_require (parser, CPP_COLON, "expected %<:%>");
+
+ tree nl = c_parser_omp_variable_list (parser, loc, kind, list, C_ORT_OMP, true);
parens.skip_until_found_close (parser);
- if (present)
+ if (present_modifier)
for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
OMP_CLAUSE_MOTION_PRESENT (c) = 1;
+ if (mapper_name)
+ {
+ tree last_new = NULL_TREE;
+ for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ last_new = c;
+
+ tree name = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_PUSH_MAPPER_NAME);
+ OMP_CLAUSE_DECL (name) = mapper_name;
+ OMP_CLAUSE_CHAIN (name) = nl;
+ nl = name;
+
+ gcc_assert (last_new);
+
+ name = build_omp_clause (input_location, OMP_CLAUSE_MAP);
+ OMP_CLAUSE_SET_MAP_KIND (name, GOMP_MAP_POP_MAPPER_NAME);
+ OMP_CLAUSE_DECL (name) = null_pointer_node;
+ OMP_CLAUSE_CHAIN (name) = OMP_CLAUSE_CHAIN (last_new);
+ OMP_CLAUSE_CHAIN (last_new) = name;
+ }
+
+ if (iterators)
+ {
+ tree block = pop_scope ();
+ if (iterators == error_mark_node)
+ iterators = NULL_TREE;
+ else
+ OMP_ITERATORS_BLOCK (iterators) = block;
+ }
+
+ if (iterators)
+ for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ OMP_CLAUSE_ITERATORS (c) = iterators;
+
return nl;
}
@@ -20876,8 +22440,7 @@ c_parser_omp_clause_init (c_parser *parser, tree list)
error_at (loc,
"missing required %<target%> and/or %<targetsync%> modifier");
- tree nl = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_INIT, list,
- false);
+ tree nl = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_INIT, list);
parens.skip_until_found_close (parser);
for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
@@ -21069,7 +22632,7 @@ c_parser_oacc_all_clauses (c_parser *parser, omp_clause_mask mask,
case PRAGMA_OACC_CLAUSE_REDUCTION:
clauses
= c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION,
- false, clauses);
+ C_ORT_ACC, clauses);
c_name = "reduction";
break;
case PRAGMA_OACC_CLAUSE_SELF:
@@ -21235,7 +22798,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
case PRAGMA_OMP_CLAUSE_IN_REDUCTION:
clauses
= c_parser_omp_clause_reduction (parser, OMP_CLAUSE_IN_REDUCTION,
- true, clauses);
+ C_ORT_OMP, clauses);
c_name = "in_reduction";
break;
case PRAGMA_OMP_CLAUSE_INDIRECT:
@@ -21281,7 +22844,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
case PRAGMA_OMP_CLAUSE_REDUCTION:
clauses
= c_parser_omp_clause_reduction (parser, OMP_CLAUSE_REDUCTION,
- true, clauses);
+ C_ORT_OMP, clauses);
c_name = "reduction";
break;
case PRAGMA_OMP_CLAUSE_SCHEDULE:
@@ -21295,7 +22858,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
case PRAGMA_OMP_CLAUSE_TASK_REDUCTION:
clauses
= c_parser_omp_clause_reduction (parser, OMP_CLAUSE_TASK_REDUCTION,
- true, clauses);
+ C_ORT_OMP, clauses);
c_name = "task_reduction";
break;
case PRAGMA_OMP_CLAUSE_UNTIED:
@@ -21397,6 +22960,10 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
clauses = c_parser_omp_clause_allocate (parser, clauses);
c_name = "allocate";
break;
+ case PRAGMA_OMP_CLAUSE_USES_ALLOCATORS:
+ clauses = c_parser_omp_clause_uses_allocators (parser, clauses);
+ c_name = "uses_allocators";
+ break;
case PRAGMA_OMP_CLAUSE_LINEAR:
clauses = c_parser_omp_clause_linear (parser, clauses);
c_name = "linear";
@@ -21430,7 +22997,7 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
c_name = "interop";
break;
case PRAGMA_OMP_CLAUSE_MAP:
- clauses = c_parser_omp_clause_map (parser, clauses);
+ clauses = c_parser_omp_clause_map (parser, clauses, GOMP_MAP_TOFROM);
c_name = "map";
break;
case PRAGMA_OMP_CLAUSE_USE_DEVICE_PTR:
@@ -21588,7 +23155,7 @@ c_parser_oacc_cache (location_t loc, c_parser *parser)
readonly = true;
}
clauses = c_parser_omp_variable_list (parser, open_loc,
- OMP_CLAUSE__CACHE_, NULL_TREE);
+ OMP_CLAUSE__CACHE_, NULL_TREE, C_ORT_ACC);
parens.skip_until_found_close (parser);
}
@@ -22457,7 +24024,7 @@ c_parser_omp_allocate (c_parser *parser)
!= get_identifier ("omp_allocator_handle_t"))
{
error_at (expr_loc,
- "%<allocator%> clause allocator expression has type "
+ "%<allocator%> clause expression has type "
"%qT rather than %<omp_allocator_handle_t%>",
TREE_TYPE (allocator));
allocator = NULL_TREE;
@@ -25890,7 +27457,9 @@ c_parser_omp_target_data (location_t loc, c_parser *parser, bool *if_p)
tree clauses
= c_parser_omp_all_clauses (parser, OMP_TARGET_DATA_CLAUSE_MASK,
- "#pragma omp target data");
+ "#pragma omp target data", false);
+ clauses = c_omp_instantiate_mappers (clauses, C_ORT_OMP);
+ clauses = c_finish_omp_clauses (clauses, C_ORT_OMP);
c_omp_adjust_map_clauses (clauses, false);
int map_seen = 0;
for (tree *pc = &clauses; *pc;)
@@ -25981,9 +27550,41 @@ c_parser_omp_target_update (location_t loc, c_parser *parser,
tree clauses
= c_parser_omp_all_clauses (parser, OMP_TARGET_UPDATE_CLAUSE_MASK,
- "#pragma omp target update");
- if (omp_find_clause (clauses, OMP_CLAUSE_TO) == NULL_TREE
- && omp_find_clause (clauses, OMP_CLAUSE_FROM) == NULL_TREE)
+ "#pragma omp target update", false);
+ clauses = c_omp_instantiate_mappers (clauses, C_ORT_OMP_UPDATE);
+ clauses = c_finish_omp_clauses (clauses, C_ORT_OMP_UPDATE);
+ bool to_clause = false, from_clause = false;
+ for (tree c = clauses;
+ c && !to_clause && !from_clause;
+ c = OMP_CLAUSE_CHAIN (c))
+ {
+ switch (OMP_CLAUSE_CODE (c))
+ {
+ case OMP_CLAUSE_TO:
+ to_clause = true;
+ break;
+ case OMP_CLAUSE_FROM:
+ from_clause = true;
+ break;
+ case OMP_CLAUSE_MAP:
+ switch (OMP_CLAUSE_MAP_KIND (c))
+ {
+ case GOMP_MAP_TO_GRID:
+ to_clause = true;
+ break;
+ case GOMP_MAP_FROM_GRID:
+ from_clause = true;
+ break;
+ default:
+ ;
+ }
+ break;
+ default:
+ ;
+ }
+ }
+
+ if (!to_clause && !from_clause)
{
error_at (loc,
"%<#pragma omp target update%> must contain at least one "
@@ -26048,7 +27649,9 @@ c_parser_omp_target_enter_data (location_t loc, c_parser *parser,
tree clauses
= c_parser_omp_all_clauses (parser, OMP_TARGET_ENTER_DATA_CLAUSE_MASK,
- "#pragma omp target enter data");
+ "#pragma omp target enter data", false);
+ clauses = c_omp_instantiate_mappers (clauses, C_ORT_OMP);
+ clauses = c_finish_omp_clauses (clauses, C_ORT_OMP);
c_omp_adjust_map_clauses (clauses, false);
int map_seen = 0;
for (tree *pc = &clauses; *pc;)
@@ -26159,6 +27762,7 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
tree clauses
= c_parser_omp_all_clauses (parser, OMP_TARGET_EXIT_DATA_CLAUSE_MASK,
"#pragma omp target exit data", false);
+ clauses = c_omp_instantiate_mappers (clauses, C_ORT_OMP_EXIT_DATA);
clauses = c_finish_omp_clauses (clauses, C_ORT_OMP_EXIT_DATA);
c_omp_adjust_map_clauses (clauses, false);
int map_seen = 0;
@@ -26242,14 +27846,15 @@ c_parser_omp_target_exit_data (location_t loc, c_parser *parser,
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IN_REDUCTION) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_THREAD_LIMIT) \
| (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR)\
- | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR))
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_HAS_DEVICE_ADDR)\
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USES_ALLOCATORS))
static bool
c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p)
{
location_t loc = c_parser_peek_token (parser)->location;
c_parser_consume_pragma (parser);
- tree *pc = NULL, stmt, block;
+ tree *pc = NULL, stmt, block, body, clauses;
if (context != pragma_stmt && context != pragma_compound)
{
@@ -26404,10 +28009,9 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p)
stmt = make_node (OMP_TARGET);
TREE_TYPE (stmt) = void_type_node;
- OMP_TARGET_CLAUSES (stmt)
- = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
- "#pragma omp target", false);
- for (tree c = OMP_TARGET_CLAUSES (stmt); c; c = OMP_CLAUSE_CHAIN (c))
+ clauses = c_parser_omp_all_clauses (parser, OMP_TARGET_CLAUSE_MASK,
+ "#pragma omp target", false);
+ for (tree c = clauses; c; c = OMP_CLAUSE_CHAIN (c))
if (OMP_CLAUSE_CODE (c) == OMP_CLAUSE_IN_REDUCTION)
{
tree nc = build_omp_clause (OMP_CLAUSE_LOCATION (c), OMP_CLAUSE_MAP);
@@ -26416,14 +28020,19 @@ c_parser_omp_target (c_parser *parser, enum pragma_context context, bool *if_p)
OMP_CLAUSE_CHAIN (nc) = OMP_CLAUSE_CHAIN (c);
OMP_CLAUSE_CHAIN (c) = nc;
}
- OMP_TARGET_CLAUSES (stmt)
- = c_finish_omp_clauses (OMP_TARGET_CLAUSES (stmt), C_ORT_OMP_TARGET);
- c_omp_adjust_map_clauses (OMP_TARGET_CLAUSES (stmt), true);
+ clauses = c_omp_instantiate_mappers (clauses, C_ORT_OMP_TARGET);
+ clauses = c_finish_omp_clauses (clauses, C_ORT_OMP_TARGET);
+ c_omp_adjust_map_clauses (clauses, true);
- pc = &OMP_TARGET_CLAUSES (stmt);
keep_next_level ();
block = c_begin_compound_stmt (true);
- add_stmt (c_parser_omp_structured_block (parser, if_p));
+ body = c_parser_omp_structured_block (parser, if_p);
+
+ c_omp_scan_mapper_bindings (loc, &clauses, body);
+
+ add_stmt (body);
+ OMP_TARGET_CLAUSES (stmt) = clauses;
+ pc = &OMP_TARGET_CLAUSES (stmt);
OMP_TARGET_BODY (stmt) = c_end_compound_stmt (loc, block, true);
SET_EXPR_LOCATION (stmt, loc);
@@ -26938,16 +28547,56 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
parens.require_close (parser);
+ const int parm_count = [&] ()
+ {
+ tree parm = TYPE_ARG_TYPES (TREE_TYPE (fndecl));
+ int parm_count = 0;
+ while (parm != NULL_TREE && parm != void_list_node)
+ {
+ ++parm_count;
+ parm = TREE_CHAIN (parm);
+ }
+ gcc_assert (!parm || parm == void_list_node);
+ return parm == void_list_node ? parm_count : 0;
+ } (); /* IILE. */
+ /* Do we care about non-variadic functions with 0 parameters? I don't think
+ we do, but lets handle for that case anyway, at least as long as we aren't
+ diagnosing for it. */
+ const bool variadic_p = TYPE_ARG_TYPES (TREE_TYPE (fndecl)) == void_list_node
+ ? false : parm_count == 0;
+
tree append_args_tree = NULL_TREE;
tree append_args_last;
- vec<tree> adjust_args_list = vNULL;
+ hash_map<int_hash<int, -1, -2>, tree> adjust_args_idxs;
bool has_match = false, has_adjust_args = false;
location_t adjust_args_loc = UNKNOWN_LOCATION;
location_t append_args_loc = UNKNOWN_LOCATION;
location_t match_loc = UNKNOWN_LOCATION;
- tree need_device_ptr_list = NULL_TREE;
tree ctx = error_mark_node;
+ tree adjust_args_list = NULL_TREE;
+ auto append_adjust_args = [chain = &adjust_args_list] (tree node) mutable
+ {
+ gcc_assert (chain && *chain == NULL_TREE);
+ *chain = node;
+ chain = &TREE_CHAIN (node);
+ };
+
+ auto compare_ranges = [&] (tree item)
+ {
+ for (tree n2 = adjust_args_list; n2; n2 = TREE_CHAIN (n2))
+ {
+ tree item2 = TREE_VALUE (n2);
+ if (TREE_CODE (TREE_VALUE (item2)) == INTEGER_CST)
+ continue;
+ else if (c_omp_numeric_ranges_always_overlap (TREE_VALUE (item2),
+ TREE_VALUE (item)))
+ /* Return the location. */
+ return TREE_PURPOSE (item2);
+ }
+ return NULL_TREE;
+ };
+
do
{
if (c_parser_next_token_is (parser, CPP_COMMA)
@@ -26992,7 +28641,8 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
if (!parens.require_open (parser))
goto fail;
-
+ /* This almost certainly causes problems with technically correct, but
+ insane functions that are variadic with no params. */
if (parms == NULL_TREE)
parms = error_mark_node;
@@ -27006,6 +28656,20 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
goto fail;
ctx = omp_check_context_selector (match_loc, ctx,
OMP_CTX_DECLARE_VARIANT);
+
+ /* The OpenMP spec says the merging rules for enclosing
+ "begin declare variant" contexts apply to "declare variant
+ directives" -- the term it uses to refer to both directive
+ forms. */
+ if (ctx != error_mark_node
+ && !vec_safe_is_empty (current_omp_declare_variant_attribute))
+ {
+ c_omp_declare_variant_attr a
+ = current_omp_declare_variant_attribute->last ();
+ tree outer_ctx = a.selector;
+ ctx = omp_merge_context_selectors (match_loc, outer_ctx, ctx,
+ OMP_CTX_DECLARE_VARIANT);
+ }
if (ctx != error_mark_node && variant != error_mark_node)
{
if (TREE_CODE (variant) != FUNCTION_DECL)
@@ -27037,62 +28701,119 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
if (c_parser_next_token_is (parser, CPP_NAME)
&& c_parser_peek_2nd_token (parser)->type == CPP_COLON)
{
- const char *p
- = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ tree modifier_id = c_parser_peek_token (parser)->value;
+ const char *p = IDENTIFIER_POINTER (modifier_id);
if (strcmp (p, "need_device_ptr") == 0
|| strcmp (p, "nothing") == 0)
{
- c_parser_consume_token (parser); // need_device_ptr
+ c_parser_consume_token (parser); // need_device_ptr / nothing
c_parser_consume_token (parser); // :
loc = c_parser_peek_token (parser)->location;
- tree list
- = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_ERROR,
- NULL_TREE);
+ const tree parm_list
+ = c_parser_omp_parm_list (parser, fndecl, parm_count);
- tree arg;
if (variant != error_mark_node)
- for (tree c = list; c != NULL_TREE; c = TREE_CHAIN (c))
+ for (tree next, n = parm_list; n != NULL_TREE; n = next)
{
- tree decl = TREE_PURPOSE (c);
- location_t arg_loc = EXPR_LOCATION (TREE_VALUE (c));
- int idx;
- for (arg = parms, idx = 0; arg != NULL;
- arg = TREE_CHAIN (arg), idx++)
- if (arg == decl)
- break;
- if (arg == NULL_TREE)
+ next = TREE_CHAIN (n);
+ TREE_CHAIN (n) = NULL_TREE;
+ TREE_PURPOSE (n) = modifier_id;
+
+ tree item = TREE_VALUE (n);
+ const location_t item_loc
+ = EXPR_LOCATION (TREE_PURPOSE (item));
+ if (TREE_CODE (TREE_VALUE (item)) == TREE_LIST)
{
- error_at (arg_loc,
- "%qD is not a function argument",
- decl);
- goto fail;
+ /* Ranges are expanded by c_parser_omp_parm_list
+ in non-variadic functions. */
+ gcc_assert (variadic_p);
+ if (tree dupe = compare_ranges (item))
+ {
+ const location_t dupe_item_loc
+ = EXPR_LOCATION (dupe);
+
+ error_at (item_loc,
+ "numeric range always overlaps with "
+ "previously specified numeric "
+ "range");
+ inform (dupe_item_loc,
+ "previously specified here");
+ }
+ else
+ append_adjust_args (n);
+ continue;
}
- if (adjust_args_list.contains (arg))
+ gcc_assert (TREE_CODE (TREE_VALUE (item))
+ == INTEGER_CST);
+ const int idx = tree_to_shwi (TREE_VALUE (item));
+ /* Indices are 0 based, c_parser_omp_parm_list is
+ supposed to handle out of range indices. */
+ gcc_assert (idx >= 0
+ && (variadic_p || idx < parm_count));
+
+ if (tree *dupe = adjust_args_idxs.get (idx))
{
- error_at (arg_loc,
- "%qD is specified more than once",
- decl);
+ const location_t prev_item_loc
+ = EXPR_LOCATION (TREE_PURPOSE (*dupe));
+ /* Ensure the wording matches that in
+ c_parser_omp_parm_list. */
+ error_at (item_loc,
+ "parameter list item specified more "
+ "than once");
+ inform (prev_item_loc,
+ "previously specified here");
+ /* FIXME: Don't fail, keep going. */
goto fail;
}
- if (strcmp (p, "need_device_ptr") == 0
- && TREE_CODE (TREE_TYPE (arg)) != POINTER_TYPE)
+ /* Unconditionally push idx so we don't emit the
+ following errors multiple times. */
+ if (adjust_args_idxs.put (idx, item))
+ gcc_unreachable ();
+
+ if (strcmp (p, "need_device_ptr") == 0)
{
- error_at (loc, "%qD is not of pointer type", decl);
- goto fail;
+ const tree parm = [&] ()
+ {
+ if (idx >= parm_count)
+ return NULL_TREE;
+ int curr_idx = 0;
+ tree parm = parms;
+ while (parm != NULL_TREE)
+ {
+ if (curr_idx == idx)
+ return parm;
+ ++curr_idx;
+ parm = TREE_CHAIN (parm);
+ }
+ /* We already confirmed a parm exists in
+ c_parser_omp_parm_list. */
+ gcc_unreachable ();
+ } (); /* IILE. */
+ /* If we don't have an argument (because the index
+ is to a variadic arg) we can't check this. */
+ if (parm
+ && TREE_CODE (TREE_TYPE (parm))
+ != POINTER_TYPE)
+ {
+ error_at (DECL_SOURCE_LOCATION (parm),
+ "%qD is not of pointer type", parm);
+ inform (item_loc, "specified here");
+ /* FIXME: Don't fail, keep going. */
+ goto fail;
+ }
+ append_adjust_args (n);
}
- adjust_args_list.safe_push (arg);
- if (strcmp (p, "need_device_ptr") == 0)
+ else if (strcmp (p, "nothing") == 0)
{
- need_device_ptr_list = chainon (
- need_device_ptr_list,
- build_tree_list (
- NULL_TREE,
- build_int_cst (
- integer_type_node,
- idx))); // Store 0-based argument index,
- // as in gimplify_call_expr
+ /* We only need to save parameter list items from a
+ clause with the nothing modifier if the function
+ is variadic. */
+ if (variadic_p)
+ append_adjust_args (n);
}
+ else
+ gcc_unreachable ();
}
}
else
@@ -27321,11 +29042,13 @@ c_finish_omp_declare_variant (c_parser *parser, tree fndecl, tree parms)
}
if ((ctx != error_mark_node && variant != error_mark_node)
- && (need_device_ptr_list || append_args_tree))
+ && (adjust_args_list || append_args_tree))
{
tree variant_decl = tree_strip_nop_conversions (variant);
- tree t = build_tree_list (need_device_ptr_list,
- NULL_TREE /* need_device_addr */);
+ tree t = build_tree_list (CHECKING_P
+ ? get_identifier ("omp adjust args idxs")
+ : NULL_TREE,
+ adjust_args_list);
TREE_CHAIN (t) = append_args_tree;
DECL_ATTRIBUTES (variant_decl)
= tree_cons (get_identifier ("omp declare variant variant args"), t,
@@ -27412,6 +29135,87 @@ c_finish_omp_declare_simd (c_parser *parser, tree fndecl, tree parms,
clauses[0].type = CPP_PRAGMA;
}
+/* This is consistent with the C++ front end. */
+
+#if !defined (NO_DOT_IN_LABEL)
+#define JOIN_STR "."
+#elif !defined (NO_DOLLAR_IN_LABEL)
+#define JOIN_STR "$"
+#else
+#define JOIN_STR "_"
+#endif
+
+/* Helper function for OpenMP "begin declare variant" directives.
+ Function definitions inside the construct need to have their names
+ mangled according to the context selector CTX. The DECLARATOR is
+ modified in place to point to a new identifier; the original name of
+ the function is returned. */
+static tree
+omp_start_variant_function (c_declarator *declarator, tree ctx)
+{
+ c_declarator *id = declarator;
+ while (id->kind != cdk_id)
+ {
+ id = id->declarator;
+ gcc_assert (id);
+ }
+ tree name = id->u.id.id;
+ id->u.id.id = omp_mangle_variant_name (name, ctx, JOIN_STR);
+ return name;
+}
+
+/* Helper function for OpenMP "begin declare variant" directives. Now
+ that we have a DECL for the variant function, and BASE_NAME for the
+ base function, add an "omp declare variant base" attribute pointing
+ at CTX to the base decl, and an "omp declare variant variant"
+ attribute to the variant DECL. */
+static void
+omp_finish_variant_function (tree decl, tree base_name, tree ctx)
+{
+ /* First look up BASE_NAME and ensure it matches DECL. */
+ tree base_decl = lookup_name (base_name);
+ if (base_decl == error_mark_node)
+ base_decl = NULL_TREE;
+ if (!base_decl)
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "no previous declaration of base function");
+ return;
+ }
+
+ if (!comptypes (TREE_TYPE (decl), TREE_TYPE (base_decl)))
+ {
+ error_at (DECL_SOURCE_LOCATION (decl),
+ "variant function definition does not match previous "
+ "declaration of %qE", base_decl);
+ return;
+ }
+
+ /* Now set the attributes on the base and variant decls for the middle
+ end. */
+ omp_check_for_duplicate_variant (DECL_SOURCE_LOCATION (decl),
+ base_decl, ctx);
+ tree construct
+ = omp_get_context_selector_list (ctx, OMP_TRAIT_SET_CONSTRUCT);
+ omp_mark_declare_variant (DECL_SOURCE_LOCATION (decl), decl, construct);
+ tree attrs = DECL_ATTRIBUTES (base_decl);
+ tree match_loc_node
+ = maybe_wrap_with_location (integer_zero_node,
+ DECL_SOURCE_LOCATION (base_decl));
+ tree loc_node = tree_cons (match_loc_node, integer_zero_node,
+ build_tree_list (match_loc_node,
+ integer_zero_node));
+ attrs = tree_cons (get_identifier ("omp declare variant base"),
+ tree_cons (decl, ctx, loc_node), attrs);
+ DECL_ATTRIBUTES (base_decl) = attrs;
+
+ /* Variant functions are essentially anonymous and cannot be referenced
+ outside the compilation unit. */
+ TREE_PUBLIC (decl) = 0;
+ DECL_COMDAT (decl) = 0;
+}
+
+
/* D should be C_TOKEN_VEC from omp::decl attribute. If it contains
a threadprivate, groupprivate, allocate or declare target directive,
return true and parse it for DECL. */
@@ -27644,7 +29448,9 @@ c_parser_omp_declare_target (c_parser *parser)
/* OpenMP 5.1
#pragma omp begin assumes clauses[optseq] new-line
- #pragma omp begin declare target clauses[optseq] new-line */
+ #pragma omp begin declare target clauses[optseq] new-line
+
+ #pragma omp begin declare variant (match context-selector) new-line */
#define OMP_BEGIN_DECLARE_TARGET_CLAUSE_MASK \
( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE_TYPE) \
@@ -27684,11 +29490,75 @@ c_parser_omp_begin (c_parser *parser)
indirect };
vec_safe_push (current_omp_declare_target_attribute, attr);
}
- else
+ else if (strcmp (p, "variant") == 0)
{
- c_parser_error (parser, "expected %<target%>");
+ c_parser_consume_token (parser);
+ const char *clause = "";
+ matching_parens parens;
+ location_t match_loc = c_parser_peek_token (parser)->location;
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ {
+ tree id = c_parser_peek_token (parser)->value;
+ clause = IDENTIFIER_POINTER (id);
+ }
+ if (strcmp (clause, "match") != 0)
+ {
+ c_parser_error (parser, "expected %<match%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
+
+ c_parser_consume_token (parser);
+
+ if (!parens.require_open (parser))
+ {
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+
+ tree ctx =
+ c_parser_omp_context_selector_specification (parser, NULL_TREE);
+ if (ctx != error_mark_node)
+ ctx = omp_check_context_selector (match_loc, ctx,
+ OMP_CTX_BEGIN_DECLARE_VARIANT);
+
+ if (ctx != error_mark_node
+ && !vec_safe_is_empty (current_omp_declare_variant_attribute))
+ {
+ c_omp_declare_variant_attr a
+ = current_omp_declare_variant_attribute->last ();
+ tree outer_ctx = a.selector;
+ ctx = omp_merge_context_selectors (match_loc, outer_ctx, ctx,
+ OMP_CTX_BEGIN_DECLARE_VARIANT);
+ }
+
+ if (ctx == error_mark_node
+ || !omp_context_selector_matches (ctx, NULL_TREE, false, true))
+ {
+ /* The context is either invalid or cannot possibly match.
+ In the latter case the spec says all code in the begin/end
+ sequence will be elided. In the former case we'll get bogus
+ errors from trying to parse it without a valid context to
+ use for name-mangling, so elide that too. */
+ c_parser_skip_to_pragma_eol (parser, false);
+ c_parser_skip_to_pragma_omp_end_declare_variant (parser);
+ return;
+ }
+ else
+ {
+ bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
+ c_omp_declare_variant_attr a = { attr_syntax, ctx };
+ vec_safe_push (current_omp_declare_variant_attribute, a);
+ }
+
+ parens.require_close (parser);
c_parser_skip_to_pragma_eol (parser);
}
+ else
+ {
+ c_parser_error (parser, "expected %<target%> or %<variant%>");
+ c_parser_skip_to_pragma_eol (parser, false);
+ }
}
else if (strcmp (p, "assumes") == 0)
{
@@ -27700,7 +29570,8 @@ c_parser_omp_begin (c_parser *parser)
}
else
{
- c_parser_error (parser, "expected %<declare target%> or %<assumes%>");
+ c_parser_error (parser, "expected %<declare target%>, "
+ "%<declare variant%>, or %<assumes%>");
c_parser_skip_to_pragma_eol (parser);
}
}
@@ -27709,7 +29580,8 @@ c_parser_omp_begin (c_parser *parser)
#pragma omp end declare target
OpenMP 5.1
- #pragma omp end assumes */
+ #pragma omp end assumes
+ #pragma omp end declare variant new-line */
static void
c_parser_omp_end (c_parser *parser)
@@ -27722,44 +29594,74 @@ c_parser_omp_end (c_parser *parser)
if (strcmp (p, "declare") == 0)
{
c_parser_consume_token (parser);
- if (c_parser_next_token_is (parser, CPP_NAME)
- && strcmp (IDENTIFIER_POINTER (c_parser_peek_token (parser)->value),
- "target") == 0)
- c_parser_consume_token (parser);
- else
+ p = "";
+ if (c_parser_next_token_is (parser, CPP_NAME))
+ p = IDENTIFIER_POINTER (c_parser_peek_token (parser)->value);
+ if (strcmp (p, "target") == 0)
{
- c_parser_error (parser, "expected %<target%>");
+ c_parser_consume_token (parser);
+ bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
c_parser_skip_to_pragma_eol (parser);
- return;
+ if (!vec_safe_length (current_omp_declare_target_attribute))
+ error_at (loc, "%<#pragma omp end declare target%> without "
+ "corresponding %<#pragma omp declare target%> or "
+ "%<#pragma omp begin declare target%>");
+ else
+ {
+ c_omp_declare_target_attr
+ a = current_omp_declare_target_attribute->pop ();
+ if (a.attr_syntax != attr_syntax)
+ {
+ if (a.attr_syntax)
+ error_at (loc,
+ "%qs in attribute syntax terminated "
+ "with %qs in pragma syntax",
+ a.device_type >= 0 ? "begin declare target"
+ : "declare target",
+ "end declare target");
+ else
+ error_at (loc,
+ "%qs in pragma syntax terminated "
+ "with %qs in attribute syntax",
+ a.device_type >= 0 ? "begin declare target"
+ : "declare target",
+ "end declare target");
+ }
+ }
}
- bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
- c_parser_skip_to_pragma_eol (parser);
- if (!vec_safe_length (current_omp_declare_target_attribute))
- error_at (loc, "%<#pragma omp end declare target%> without "
- "corresponding %<#pragma omp declare target%> or "
- "%<#pragma omp begin declare target%>");
- else
+ else if (strcmp (p, "variant") == 0)
{
- c_omp_declare_target_attr
- a = current_omp_declare_target_attribute->pop ();
- if (a.attr_syntax != attr_syntax)
+ c_parser_consume_token (parser);
+ bool attr_syntax = parser->in_omp_attribute_pragma != NULL;
+ c_parser_skip_to_pragma_eol (parser);
+ if (!vec_safe_length (current_omp_declare_variant_attribute))
+ error_at (loc, "%<#pragma omp end declare variant%> without "
+ "corresponding %<#pragma omp begin declare variant%>");
+ else
{
- if (a.attr_syntax)
- error_at (loc,
- "%qs in attribute syntax terminated "
- "with %qs in pragma syntax",
- a.device_type >= 0 ? "begin declare target"
- : "declare target",
- "end declare target");
- else
- error_at (loc,
- "%qs in pragma syntax terminated "
- "with %qs in attribute syntax",
- a.device_type >= 0 ? "begin declare target"
- : "declare target",
- "end declare target");
+ c_omp_declare_variant_attr
+ a = current_omp_declare_variant_attribute->pop ();
+ if (a.attr_syntax != attr_syntax)
+ {
+ if (a.attr_syntax)
+ error_at (loc,
+ "%<begin declare variant%> in attribute syntax "
+ "terminated with "
+ "%<end declare variant%> in pragma syntax");
+ else
+ error_at (loc,
+ "%<begin declare variant%> in pragma syntax "
+ "terminated with "
+ "%<end declare variant%> in attribute syntax");
+ }
}
}
+ else
+ {
+ c_parser_error (parser, "expected %<target%> or %<variant%>");
+ c_parser_skip_to_pragma_eol (parser);
+ return;
+ }
}
else if (strcmp (p, "assumes") == 0)
{
@@ -27795,6 +29697,151 @@ c_parser_omp_end (c_parser *parser)
}
}
+/* OpenMP 5.0
+ #pragma omp declare mapper ([mapper-identifier :] type var) \
+ [clause [ [,] clause ] ... ] new-line */
+
+static void
+c_parser_omp_declare_mapper (c_parser *parser, enum pragma_context context)
+{
+ tree type, mapper_name = NULL_TREE, var = NULL_TREE, stmt, stmtlist;
+ tree maplist = NULL_TREE, mapper_id, mapper_decl, t;
+ c_token *token;
+
+ if (context == pragma_struct || context == pragma_param)
+ {
+ error ("%<#pragma omp declare reduction%> not at file or block scope");
+ goto fail;
+ }
+
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ goto fail;
+
+ token = c_parser_peek_token (parser);
+
+ if (c_parser_peek_2nd_token (parser)->type == CPP_COLON)
+ {
+ switch (token->type)
+ {
+ case CPP_NAME:
+ mapper_name = token->value;
+ c_parser_consume_token (parser);
+ break;
+ case CPP_KEYWORD:
+ if (token->keyword == RID_DEFAULT)
+ {
+ mapper_name = NULL_TREE;
+ c_parser_consume_token (parser);
+ break;
+ }
+ /* Fallthrough. */
+ default:
+ error_at (token->location, "expected identifier or %<default%>");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+
+ if (!c_parser_require (parser, CPP_COLON, "expected %<:%>"))
+ goto fail;
+ }
+
+ mapper_id = c_omp_mapper_id (mapper_name);
+ mapper_decl = c_omp_mapper_decl (mapper_id);
+
+ {
+ location_t loc = c_parser_peek_token (parser)->location;
+ struct c_type_name *ctype = c_parser_type_name (parser);
+ type = groktypename (ctype, NULL, NULL);
+ if (type == error_mark_node)
+ goto fail;
+ if (TREE_CODE (type) != RECORD_TYPE
+ && TREE_CODE (type) != UNION_TYPE)
+ {
+ error_at (loc, "%qT is not a struct or union type in "
+ "%<#pragma omp declare mapper%>", type);
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+ for (tree t = DECL_INITIAL (mapper_decl); t; t = TREE_CHAIN (t))
+ if (comptypes (TREE_PURPOSE (t), type))
+ {
+ error_at (loc, "redeclaration of %qs %<#pragma omp declare "
+ "mapper%> for type %qT", IDENTIFIER_POINTER (mapper_id)
+ + sizeof ("omp declare mapper ") - 1,
+ type);
+ tree prevmapper = TREE_VALUE (t);
+ /* Hmm, this location might not be very accurate. */
+ location_t ploc
+ = DECL_SOURCE_LOCATION (OMP_DECLARE_MAPPER_DECL (prevmapper));
+ error_at (ploc, "previous %<#pragma omp declare mapper%>");
+ c_parser_skip_to_pragma_eol (parser, false);
+ return;
+ }
+ }
+
+ token = c_parser_peek_token (parser);
+ if (token->type == CPP_NAME)
+ {
+ var = build_decl (token->location, VAR_DECL, token->value, type);
+ c_parser_consume_token (parser);
+ DECL_ARTIFICIAL (var) = 1;
+ }
+ else
+ {
+ error_at (token->location, "expected identifier");
+ goto fail;
+ }
+
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN, "expected %<)%>"))
+ goto fail;
+
+ push_scope ();
+ stmtlist = push_stmt_list ();
+ pushdecl (var);
+ DECL_CONTEXT (var) = current_function_decl;
+
+ while (c_parser_next_token_is_not (parser, CPP_PRAGMA_EOL))
+ {
+ location_t here;
+ pragma_omp_clause c_kind;
+ here = c_parser_peek_token (parser)->location;
+ c_kind = c_parser_omp_clause_name (parser);
+ if (c_kind != PRAGMA_OMP_CLAUSE_MAP)
+ {
+ error_at (here, "unexpected clause");
+ goto fail;
+ }
+ maplist = c_parser_omp_clause_map (parser, maplist, GOMP_MAP_UNSET);
+ }
+
+ if (maplist == NULL_TREE)
+ {
+ error_at (input_location, "missing %<map%> clause");
+ goto fail;
+ }
+
+ stmt = make_node (OMP_DECLARE_MAPPER);
+ TREE_TYPE (stmt) = type;
+ OMP_DECLARE_MAPPER_ID (stmt) = mapper_name;
+ OMP_DECLARE_MAPPER_DECL (stmt) = var;
+ OMP_DECLARE_MAPPER_CLAUSES (stmt) = maplist;
+
+ add_stmt (stmt);
+
+ pop_stmt_list (stmtlist);
+ pop_scope ();
+
+ c_parser_skip_to_pragma_eol (parser);
+
+ t = tree_cons (type, stmt, DECL_INITIAL (mapper_decl));
+ DECL_INITIAL (mapper_decl) = t;
+
+ return;
+
+ fail:
+ c_parser_skip_to_pragma_eol (parser);
+}
+
/* OpenMP 4.0
#pragma omp declare reduction (reduction-id : typename-list : expression) \
initializer-clause[opt] new-line
@@ -28186,6 +30233,12 @@ c_parser_omp_declare (c_parser *parser, enum pragma_context context)
c_parser_omp_declare_reduction (parser, context);
return false;
}
+ if (strcmp (p, "mapper") == 0)
+ {
+ c_parser_consume_token (parser);
+ c_parser_omp_declare_mapper (parser, context);
+ return false;
+ }
if (!flag_openmp) /* flag_openmp_simd */
{
c_parser_skip_to_pragma_eol (parser, false);