aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorSandra Loosemore <sloosemore@baylibre.com>2025-02-09 21:34:36 +0000
committerSandra Loosemore <sloosemore@baylibre.com>2025-05-15 20:25:51 +0000
commitd5a1822a5ccaa2ce7c35f04fcdcedfe92e209d84 (patch)
treefcbe8a463e986d5b9654d3952a620ceaa670d43c /gcc
parent295dd6f754aaccacfe1708d962373ed8be3717dc (diff)
downloadgcc-d5a1822a5ccaa2ce7c35f04fcdcedfe92e209d84.zip
gcc-d5a1822a5ccaa2ce7c35f04fcdcedfe92e209d84.tar.gz
gcc-d5a1822a5ccaa2ce7c35f04fcdcedfe92e209d84.tar.bz2
OpenMP: C front end support for "begin declare variant"
gcc/c/ChangeLog * c-decl.cc (current_omp_declare_variant_attribute): Define. * c-lang.h (struct c_omp_declare_variant_attr): Declare. (current_omp_declare_variant_attribute): Declare. * c-parser.cc (c_parser_skip_to_pragma_omp_end_declare_variant): New. (c_parser_translation_unit): Check for "omp begin declare variant" with no matching "end". (c_parser_declaration_or_fndef): Handle functions in "omp begin declare variant" block. (c_finish_omp_declare_variant): Merge context selectors with surrounding "omp begin declare variant". (JOIN_STR): Define. (omp_start_variant_function): New. (omp_finish_variant_function): New. (c_parser_omp_begin): Handle "omp begin declare variant". (c_parser_omp_end): Likewise. Co-Authored-By: Julian Brown <julian@codesourcery.com>
Diffstat (limited to 'gcc')
-rw-r--r--gcc/c/c-decl.cc3
-rw-r--r--gcc/c/c-lang.h8
-rw-r--r--gcc/c/c-parser.cc343
3 files changed, 318 insertions, 36 deletions
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b8af128..00cf955 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -163,6 +163,9 @@ vec<c_omp_declare_target_attr, va_gc> *current_omp_declare_target_attribute;
we are in. */
vec<c_omp_begin_assumes_data, va_gc> *current_omp_begin_assumes;
+/* Vector of "omp begin/end declare variant" blocks we are in. */
+vec<c_omp_declare_variant_attr, va_gc> *current_omp_declare_variant_attribute;
+
/* Vector of loop names with C_DECL_LOOP_NAME or C_DECL_SWITCH_NAME marked
LABEL_DECL as the last and canonical for each loop or switch. */
static vec<tree> loop_names;
diff --git a/gcc/c/c-lang.h b/gcc/c/c-lang.h
index 4b93d18..cd68fc0 100644
--- a/gcc/c/c-lang.h
+++ b/gcc/c/c-lang.h
@@ -72,6 +72,11 @@ struct GTY(()) c_omp_begin_assumes_data {
bool attr_syntax;
};
+struct GTY(()) c_omp_declare_variant_attr {
+ bool attr_syntax;
+ tree selector;
+};
+
/* If non-empty, implicit "omp declare target" attribute is added into the
attribute lists. */
extern GTY(()) vec<c_omp_declare_target_attr, va_gc>
@@ -80,5 +85,8 @@ extern GTY(()) vec<c_omp_declare_target_attr, va_gc>
#pragma omp end assumes (and how many times when nested). */
extern GTY(()) vec<c_omp_begin_assumes_data, va_gc>
*current_omp_begin_assumes;
+/* And similarly for #pragma omp begin/end declare variant. */
+extern GTY(()) vec<c_omp_declare_variant_attr, va_gc>
+ *current_omp_declare_variant_attribute;
#endif /* ! GCC_C_LANG_H */
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 00ad861..6d607e9 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. */
@@ -27727,6 +27805,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)
@@ -28133,6 +28225,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. */
@@ -28365,7 +28538,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) \
@@ -28405,11 +28580,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)
{
@@ -28421,7 +28660,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);
}
}
@@ -28430,7 +28670,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)
@@ -28443,44 +28684,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)
{