aboutsummaryrefslogtreecommitdiff
path: root/gcc/c
diff options
context:
space:
mode:
authorTobias Burnus <tburnus@baylibre.com>2024-11-22 15:30:53 +0100
committerTobias Burnus <tburnus@baylibre.com>2024-11-22 15:30:53 +0100
commit8f0c8e577a56891fa104c818834ddafe268722bb (patch)
treeb23eca9aa95f8ff60434daabf5c57a08baf953dd /gcc/c
parent8d7f2d53c81970c50a4b9bc592ce360563ae192b (diff)
downloadgcc-8f0c8e577a56891fa104c818834ddafe268722bb.zip
gcc-8f0c8e577a56891fa104c818834ddafe268722bb.tar.gz
gcc-8f0c8e577a56891fa104c818834ddafe268722bb.tar.bz2
OpenMP: 'interop' construct - add C/C++ parser support, improve Fortran parsing
Add middle end support for the 'interop' directive and the 'init', 'use', and 'destroy' clauses - but fail with a sorry, unimplemented in gimplify.cc. For Fortran, generate the tree code, update the internal representation, add some more diagnostic checks and update for newer specification changes ('fr' only takes a single value, but it integer expressions are permitted again [like with the old syntax] not only constant identifiers). For C and C++, this patch adds the full parser support for 'interop'. Still missing is actually handling the directive in the middle end and in libgomp. The GOMP_INTEROP_IFR_* internal values have been changed to have space for vendor specific values that are adjacent to the existing values but negative, if needed. gcc/c-family/ChangeLog: * c-common.h (enum c_omp_region_type): Add C_ORT_INTEROP and C_ORT_OMP_INTEROP. (c_omp_interop_t_p): New prototype. * c-omp.cc (c_omp_interop_t_p): Check whether the type is omp_interop_t. (c_omp_directives): Uncomment 'interop'. * c-pragma.cc (omp_pragmas): Add 'interop'. * c-pragma.h (enum pragma_kind): Add PRAGMA_OMP_INTEROP. (enum pragma_omp_clause): Add init, use, and destroy clauses. gcc/c/ChangeLog: * c-parser.cc (INCLUDE_STRING): Define. (c_parser_pragma): Handle 'interop' directive. (c_parser_omp_clause_name): Handle init, use, and destroy clauses. (c_parser_omp_all_clauses): Likewise; use C_ORT_OMP_INTEROP, if 'use' is permitted, for c_finish_omp_clauses. (c_parser_omp_clause_destroy, c_parser_omp_modifier_prefer_type, c_parser_omp_clause_init, c_parser_omp_clause_use, OMP_INTEROP_CLAUSE_MASK, c_parser_omp_interop): New. * c-typeck.cc (c_finish_omp_clauses): Add missing OPT_Wopenmp to a warning; handle new clauses. gcc/cp/ChangeLog: * parser.cc (INCLUDE_STRING): Define. (cp_parser_omp_clause_name): Handle init, use, and destroy clauses. (cp_parser_omp_all_clauses): Likewise; use C_ORT_OMP_INTEROP, if 'use' is permitted, for c_finish_omp_clauses. (cp_parser_omp_modifier_prefer_type, cp_parser_omp_clause_init, OMP_INTEROP_CLAUSE_MASK, cp_parser_omp_interop): New. (cp_parser_pragma): Handle 'interop' directive. * pt.cc (tsubst_omp_clauses): Handle init, use, and destroy clauses. (tsubst_stmt): Handle OMP_INTEROP. * semantics.cc (cp_omp_init_prefer_type_update): New. (finish_omp_clauses): Handle init, use, and destroy clauses and add clause check for 'depend' on 'interop'. gcc/fortran/ChangeLog: * gfortran.h (gfc_omp_namelist): Cleanup interop internal representation. * dump-parse-tree.cc (show_omp_namelist): Update for changed internal representation. * match.cc (gfc_free_omp_namelist): Likewise. * openmp.cc (gfc_match_omp_prefer_type, gfc_match_omp_init): Likewise; also handle some corner cases better and update for newer 6.0 changes related to 'fr'. (resolve_omp_clauses): Add type-check for interop variables. * trans-openmp.cc (gfc_trans_omp_clauses): Handle init, use and destroy clauses. (gfc_trans_openmp_interop): New. (gfc_trans_omp_directive): Call it. gcc/ChangeLog: * gimplify.cc (gimplify_expr): Handle OMP_INTEROP by printing "sorry, uninplemented". * omp-api.h (omp_get_fr_id_from_name): Change return type to 'char'. * omp-general.cc (omp_get_fr_id_from_name): Likewise; return GOMP_INTEROP_IFR_UNKNOWN not 0 if not found. (omp_get_name_from_fr_id): Return "<unknown>" not NULL if not found (used for dumps). * tree-core.h (enum omp_clause_code): Add OMP_CLAUSE_DESTROY, OMP_CLAUSE_USE, and OMP_CLAUSE_INIT. * tree-pretty-print.cc (dump_omp_init_prefer_type): New. (dump_omp_clause): Handle init, use and destroy clauses. (dump_generic_node): Handle interop directive. * tree.cc (omp_clause_num_ops, omp_clause_code_name): Add new init/use/destroy clauses. * tree.def (OACC_LOOP): Fix comment. (OMP_INTEROP): Add. * tree.h (OMP_INTEROP_CLAUSES, OMP_CLAUSE_INIT_TARGET, OMP_CLAUSE_INIT_TARGETSYNC, OMP_CLAUSE_INIT_PREFER_TYPE): New. include/ChangeLog: * gomp-constants.h (GOMP_INTEROP_IFR_NONE): Rename ... (GOMP_INTEROP_IFR_UNKNOWN): ... to this. And change value. (GOMP_INTEROP_IFR_SEPARATOR): Likewise. gcc/testsuite/ChangeLog: * gfortran.dg/gomp/interop-1.f90: Update for parser changes, spec changes and add new tests. * gfortran.dg/gomp/interop-2.f90: Likewise. * gfortran.dg/gomp/interop-3.f90: Likewise. * c-c++-common/gomp/interop-1.c: New test. * c-c++-common/gomp/interop-2.c: New test. * c-c++-common/gomp/interop-3.c: New test. * c-c++-common/gomp/interop-4.c: New test. * g++.dg/gomp/interop-5.C: New test. * gfortran.dg/gomp/interop-4.f90: New test.
Diffstat (limited to 'gcc/c')
-rw-r--r--gcc/c/c-parser.cc437
-rw-r--r--gcc/c/c-typeck.cc47
2 files changed, 483 insertions, 1 deletions
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index f716c56..ca4a6b3 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -37,6 +37,7 @@ along with GCC; see the file COPYING3. If not see
#include "config.h"
#define INCLUDE_MEMORY
+#define INCLUDE_STRING
#include "system.h"
#include "coretypes.h"
#include "target.h"
@@ -1753,6 +1754,7 @@ static void c_parser_omp_allocate (c_parser *);
static void c_parser_omp_assumes (c_parser *);
static bool c_parser_omp_ordered (c_parser *, enum pragma_context, bool *);
static tree c_parser_omp_dispatch (location_t, c_parser *);
+static void c_parser_omp_interop (c_parser *);
static void c_parser_oacc_routine (c_parser *, enum pragma_context);
/* These Objective-C parser functions are only ever called when
@@ -15384,6 +15386,15 @@ c_parser_pragma (c_parser *parser, enum pragma_context context, bool *if_p,
c_parser_omp_flush (parser);
return false;
+ case PRAGMA_OMP_INTEROP:
+ if (context != pragma_compound)
+ {
+ construct = "omp interop";
+ goto in_compound;
+ }
+ c_parser_omp_interop (parser);
+ return false;
+
case PRAGMA_OMP_TASKWAIT:
if (context != pragma_compound)
{
@@ -15711,6 +15722,8 @@ c_parser_omp_clause_name (c_parser *parser)
result = PRAGMA_OACC_CLAUSE_DELETE;
else if (!strcmp ("depend", p))
result = PRAGMA_OMP_CLAUSE_DEPEND;
+ else if (!strcmp ("destroy", p))
+ result = PRAGMA_OMP_CLAUSE_DESTROY;
else if (!strcmp ("detach", p))
result = PRAGMA_OACC_CLAUSE_DETACH;
else if (!strcmp ("device", p))
@@ -15769,6 +15782,8 @@ c_parser_omp_clause_name (c_parser *parser)
result = PRAGMA_OACC_CLAUSE_INDEPENDENT;
else if (!strcmp ("indirect", p))
result = PRAGMA_OMP_CLAUSE_INDIRECT;
+ else if (!strcmp ("init", p))
+ result = PRAGMA_OMP_CLAUSE_INIT;
else if (!strcmp ("is_device_ptr", p))
result = PRAGMA_OMP_CLAUSE_IS_DEVICE_PTR;
break;
@@ -15889,6 +15904,8 @@ c_parser_omp_clause_name (c_parser *parser)
result = PRAGMA_OMP_CLAUSE_UNIFORM;
else if (!strcmp ("untied", p))
result = PRAGMA_OMP_CLAUSE_UNTIED;
+ else if (!strcmp ("use", p))
+ result = PRAGMA_OMP_CLAUSE_USE;
else if (!strcmp ("use_device", p))
result = PRAGMA_OACC_CLAUSE_USE_DEVICE;
else if (!strcmp ("use_device_addr", p))
@@ -20172,6 +20189,386 @@ c_parser_omp_clause_detach (c_parser *parser, tree list)
return u;
}
+/* OpenMP 5.0:
+ destroy ( variable-list ) */
+
+static tree
+c_parser_omp_clause_destroy (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_DESTROY, list);
+}
+
+/* OpenMP 5.1:
+ prefer_type ( const-int-expr-or-string-literal-list )
+
+ OpenMP 6.0:
+ prefer_type ( { preference-selector-list }, { ... } )
+
+ with preference-selector being:
+ fr ( identifier-or-string-literal-list )
+ attr ( string-list )
+
+ Data format:
+ For the foreign runtime identifiers, string values are converted to
+ their integer value; unknown string or integer values are set to
+ GOMP_INTEROP_IFR_KNOWN.
+
+ Each item (a) GOMP_INTEROP_IFR_SEPARATOR
+ (b) for any 'fr', its integer value.
+ Note: Spec only permits 1 'fr' entry (6.0; changed after TR13)
+ (c) GOMP_INTEROP_IFR_SEPARATOR
+ (d) list of \0-terminated non-empty strings for 'attr'
+ (e) '\0'
+ Tailing '\0'. */
+
+static tree
+c_parser_omp_modifier_prefer_type (c_parser *parser)
+{
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return error_mark_node;
+
+ std::string str;
+
+ /* Old Format: const-int-expr-or-string-literal-list */
+ if (!c_parser_next_token_is (parser, CPP_OPEN_BRACE))
+ while (true)
+ {
+ str += (char) GOMP_INTEROP_IFR_SEPARATOR;
+ if (c_parser_next_token_is (parser, CPP_STRING))
+ {
+ c_expr cval = c_parser_string_literal (parser, false, false);
+ if (cval.value == error_mark_node)
+ return error_mark_node;
+ if ((size_t) TREE_STRING_LENGTH (cval.value)
+ != strlen (TREE_STRING_POINTER (cval.value)) + 1)
+ {
+ error_at (cval.get_location (), "string literal must "
+ "not contain %<\\0%>");
+ parser->error = true;
+ return error_mark_node;
+ }
+
+ char c = omp_get_fr_id_from_name (TREE_STRING_POINTER (cval.value));
+ if (c == GOMP_INTEROP_IFR_UNKNOWN)
+ warning_at (cval.get_location (), OPT_Wopenmp,
+ "unknown foreign runtime identifier %qs",
+ TREE_STRING_POINTER (cval.value));
+ str += c;
+ }
+ else
+ {
+ c_expr cval = c_parser_expr_no_commas (parser, NULL);
+ tree value = c_fully_fold (cval.value, false, NULL);
+ if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+ && TREE_CODE (value) != INTEGER_CST)
+ value = convert_lvalue_to_rvalue (cval.get_start (), cval,
+ false, true).value;
+ if (TREE_CODE (value) != INTEGER_CST
+ || !tree_fits_shwi_p (value))
+ {
+ c_parser_error (parser, "expected string literal or constant "
+ "integer expression");
+ return error_mark_node;
+ }
+ HOST_WIDE_INT n = tree_to_shwi (value);
+ if (n < 1 || n > GOMP_INTEROP_IFR_LAST)
+ {
+ warning_at (cval.get_location (), OPT_Wopenmp,
+ "unknown foreign runtime identifier %qwd", n);
+ n = GOMP_INTEROP_IFR_UNKNOWN;
+ }
+ str += (char) n;
+ }
+ str += (char) GOMP_INTEROP_IFR_SEPARATOR;
+ str += '\0';
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN,
+ "expected %<,%> or %<)%>"))
+ return error_mark_node;
+ str += '\0';
+ tree res = build_string (str.length (), str.data ());
+ TREE_TYPE (res) = build_array_type_nelts (unsigned_char_type_node,
+ str.length ());
+ return res;
+ }
+
+ /* New format. */
+ std::string str2;
+ while (true)
+ {
+ if (!c_parser_require (parser, CPP_OPEN_BRACE, "expected %<{%>"))
+ return error_mark_node;
+ str += (char) GOMP_INTEROP_IFR_SEPARATOR;
+ str2.clear ();
+ bool has_fr = false;
+ while (true)
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ if (tok->type != CPP_NAME
+ || (strcmp("fr", IDENTIFIER_POINTER (tok->value)) != 0
+ && strcmp("attr", IDENTIFIER_POINTER (tok->value)) != 0))
+ {
+ c_parser_error (parser, "expected %<fr%> or %<attr%> preference "
+ "selector");
+ return error_mark_node;
+ }
+ c_parser_consume_token (parser);
+ bool is_fr = IDENTIFIER_POINTER (tok->value)[0] == 'f';
+ if (is_fr && has_fr)
+ {
+ c_parser_error (parser, "duplicated %<fr%> preference selector");
+ return error_mark_node;
+ }
+ if (!c_parser_require (parser, CPP_OPEN_PAREN, "expected %<(%>"))
+ return error_mark_node;
+ while (true)
+ {
+ if (c_parser_next_token_is (parser, CPP_STRING))
+ {
+ c_expr cval = c_parser_string_literal (parser, false, false);
+ tree value = cval.value;
+ if (value == error_mark_node)
+ return error_mark_node;
+ if ((size_t) TREE_STRING_LENGTH (value)
+ != strlen (TREE_STRING_POINTER (value)) + 1)
+ {
+ error_at (cval.get_location (), "string literal must "
+ "not contain %<\\0%>");
+ parser->error = true;
+ return error_mark_node;
+ }
+ if (!is_fr)
+ {
+ if (!startswith (TREE_STRING_POINTER (value), "ompx_"))
+ {
+ error_at (cval.get_location (),
+ "%<attr%> string literal must start with "
+ "%<ompx_%>");
+ parser->error = true;
+ return error_mark_node;
+ }
+ if (strchr (TREE_STRING_POINTER (value), ','))
+ {
+ error_at (cval.get_location (),
+ "%<attr%> string literal must not contain "
+ "a comma");
+ parser->error = true;
+ return error_mark_node;
+ }
+ str2 += TREE_STRING_POINTER (value);
+ str2 += '\0';
+ }
+ else
+ {
+ if (*TREE_STRING_POINTER (value) == '\0')
+ {
+ c_parser_error (parser, "non-empty string literal expected");
+ return error_mark_node;
+ }
+ char c = omp_get_fr_id_from_name (TREE_STRING_POINTER (value));
+ if (c == GOMP_INTEROP_IFR_UNKNOWN)
+ warning_at (cval.get_location (), OPT_Wopenmp,
+ "unknown foreign runtime identifier %qs",
+ TREE_STRING_POINTER (value));
+ str += c;
+ has_fr = true;
+ }
+ }
+ else if (!is_fr)
+ {
+ c_parser_error (parser, "expected string literal");
+ return error_mark_node;
+ }
+ else
+ {
+ c_expr cval = c_parser_expr_no_commas (parser, NULL);
+ tree value = c_fully_fold (cval.value, false, NULL);
+ if (INTEGRAL_TYPE_P (TREE_TYPE (value))
+ && TREE_CODE (value) != INTEGER_CST)
+ value = convert_lvalue_to_rvalue (cval.get_start (), cval,
+ false, true).value;
+
+ if (TREE_CODE (value) != INTEGER_CST
+ || !tree_fits_shwi_p (value))
+ {
+ c_parser_error (parser, "expected string literal or "
+ "constant integer expression");
+ return error_mark_node;
+ }
+ HOST_WIDE_INT n = tree_to_shwi (value);
+ if (n < 1 || n > GOMP_INTEROP_IFR_LAST)
+ {
+ warning_at (cval.get_location (), OPT_Wopenmp,
+ "unknown foreign runtime identifier %qwd", n);
+ n = GOMP_INTEROP_IFR_UNKNOWN;
+ }
+ str += (char) n;
+ has_fr = true;
+ }
+ if (!is_fr
+ && c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ if (!c_parser_require (parser, CPP_CLOSE_PAREN,
+ is_fr ? G_("expected %<)%>")
+ : G_("expected %<)%> or %<,%>")))
+ return error_mark_node;
+ break;
+ }
+ if (c_parser_next_token_is (parser, CPP_COMMA))
+ {
+ c_parser_consume_token (parser);
+ continue;
+ }
+ if (c_parser_next_token_is (parser, CPP_CLOSE_BRACE))
+ break;
+ c_parser_error (parser, "expected %<,%> or %<}%>");
+ return error_mark_node;
+ }
+ str += (char) GOMP_INTEROP_IFR_SEPARATOR;
+ str += str2;
+ str += '\0';
+ c_parser_consume_token (parser);
+ if (c_parser_next_token_is (parser, CPP_CLOSE_PAREN))
+ break;
+ if (!c_parser_require (parser, CPP_COMMA, "expected %<)%> or %<,%>"))
+ return error_mark_node;
+ }
+ c_parser_consume_token (parser);
+ str += '\0';
+ tree res = build_string (str.length (), str.data ());
+ TREE_TYPE (res) = build_array_type_nelts (unsigned_char_type_node,
+ str.length ());
+ return res;
+}
+
+/* OpenMP 5.1:
+ init ( [init-modifier-list : ] variable-list )
+
+ Modifiers:
+ target
+ targetsync
+ prefer_type (preference-specification) */
+
+static tree
+c_parser_omp_clause_init (c_parser *parser, tree list)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+
+ matching_parens parens;
+ if (!parens.require_open (parser))
+ return list;
+
+ unsigned pos = 0, raw_pos = 1;
+ while (c_parser_peek_nth_token_raw (parser, raw_pos)->type == CPP_NAME)
+ {
+ pos++; raw_pos++;
+ if (c_parser_peek_nth_token_raw (parser, raw_pos)->type == CPP_OPEN_PAREN)
+ {
+ raw_pos++;
+ c_parser_check_balanced_raw_token_sequence (parser, &raw_pos);
+ if (c_parser_peek_nth_token_raw (parser, raw_pos)->type != CPP_CLOSE_PAREN)
+ {
+ pos = 0;
+ break;
+ }
+ raw_pos++;
+ }
+ if (c_parser_peek_nth_token_raw (parser, raw_pos)->type == CPP_COLON)
+ break;
+ if (c_parser_peek_nth_token_raw (parser, raw_pos)->type != CPP_COMMA)
+ {
+ pos = 0;
+ break;
+ }
+ pos++;
+ raw_pos++;
+ }
+
+ bool target = false;
+ bool targetsync = false;
+ tree prefer_type_tree = NULL_TREE;
+
+ for (unsigned pos2 = 0; pos2 < pos; ++pos2)
+ {
+ 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 ("targetsync", p) == 0)
+ {
+ if (targetsync)
+ error_at (tok->location, "duplicate %<targetsync%> modifier");
+ targetsync = true;
+ c_parser_consume_token (parser);
+ }
+ else if (strcmp ("target", p) == 0)
+ {
+ if (target)
+ error_at (tok->location, "duplicate %<target%> modifier");
+ target = true;
+ c_parser_consume_token (parser);
+ }
+ else if (strcmp ("prefer_type", p) == 0)
+ {
+ if (prefer_type_tree != NULL_TREE)
+ error_at (tok->location, "duplicate %<prefer_type%> modifier");
+ c_parser_consume_token (parser);
+ prefer_type_tree = c_parser_omp_modifier_prefer_type (parser);
+ if (prefer_type_tree == error_mark_node)
+ return list;
+ }
+ else
+ {
+ c_parser_error (parser, "%<init%> clause with modifier other than "
+ "%<prefer_type%>, %<target%> or "
+ "%<targetsync%>");
+ parens.skip_until_found_close (parser);
+ return list;
+ }
+ }
+ if (pos)
+ {
+ c_token *tok = c_parser_peek_token (parser);
+ gcc_checking_assert (tok->type == CPP_COLON);
+ c_parser_consume_token (parser);
+ }
+
+ tree nl = c_parser_omp_variable_list (parser, loc, OMP_CLAUSE_INIT, list,
+ false);
+ parens.skip_until_found_close (parser);
+
+ for (tree c = nl; c != list; c = OMP_CLAUSE_CHAIN (c))
+ {
+ if (target)
+ OMP_CLAUSE_INIT_TARGET (c) = 1;
+ if (targetsync)
+ OMP_CLAUSE_INIT_TARGETSYNC (c) = 1;
+ if (prefer_type_tree)
+ OMP_CLAUSE_INIT_PREFER_TYPE (c) = prefer_type_tree;
+ }
+ return nl;
+}
+
+/* OpenMP 5.0:
+ use ( variable-list ) */
+
+static tree
+c_parser_omp_clause_use (c_parser *parser, tree list)
+{
+ return c_parser_omp_var_list_parens (parser, OMP_CLAUSE_USE, list);
+}
+
/* Parse all OpenACC clauses. The set clauses allowed by the directive
is a bitmask in MASK. Return the list of clauses found. */
@@ -20667,6 +21064,18 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
clauses = c_parser_omp_clause_doacross (parser, clauses);
c_name = "doacross";
break;
+ case PRAGMA_OMP_CLAUSE_DESTROY:
+ clauses = c_parser_omp_clause_destroy (parser, clauses);
+ c_name = "destroy";
+ break;
+ case PRAGMA_OMP_CLAUSE_INIT:
+ clauses = c_parser_omp_clause_init (parser, clauses);
+ c_name = "init";
+ break;
+ case PRAGMA_OMP_CLAUSE_USE:
+ clauses = c_parser_omp_clause_use (parser, clauses);
+ c_name = "use";
+ break;
case PRAGMA_OMP_CLAUSE_MAP:
clauses = c_parser_omp_clause_map (parser, clauses);
c_name = "map";
@@ -20773,6 +21182,8 @@ c_parser_omp_all_clauses (c_parser *parser, omp_clause_mask mask,
{
if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_UNIFORM)) != 0)
return c_finish_omp_clauses (clauses, C_ORT_OMP_DECLARE_SIMD);
+ if ((mask & (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE)) != 0)
+ return c_finish_omp_clauses (clauses, C_ORT_OMP_INTEROP);
return c_finish_omp_clauses (clauses, C_ORT_OMP);
}
@@ -24109,6 +24520,32 @@ c_parser_omp_masked (location_t loc, c_parser *parser,
clauses);
}
+/* OpenMP 5.1:
+ # pragma omp interop clauses[opt] new-line */
+
+#define OMP_INTEROP_CLAUSE_MASK \
+ ( (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEPEND) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DESTROY) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_DEVICE) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_INIT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_NOWAIT) \
+ | (OMP_CLAUSE_MASK_1 << PRAGMA_OMP_CLAUSE_USE))
+
+static void
+c_parser_omp_interop (c_parser *parser)
+{
+ location_t loc = c_parser_peek_token (parser)->location;
+ c_parser_consume_pragma (parser);
+ tree clauses = c_parser_omp_all_clauses (parser,
+ OMP_INTEROP_CLAUSE_MASK,
+ "#pragma omp interop");
+ tree stmt = make_node (OMP_INTEROP);
+ TREE_TYPE (stmt) = void_type_node;
+ OMP_INTEROP_CLAUSES (stmt) = clauses;
+ SET_EXPR_LOCATION (stmt, loc);
+ add_stmt (stmt);
+}
+
/* OpenMP 2.5:
# pragma omp ordered new-line
structured-block
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index dd6caf6..f6f63ca 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -15670,6 +15670,10 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
tree *full_seen = NULL;
bool partial_seen = false;
bool openacc = (ort & C_ORT_ACC) != 0;
+ bool init_seen = false;
+ bool init_use_destroy_seen = false;
+ tree init_no_targetsync_clause = NULL_TREE;
+ tree depend_clause = NULL_TREE;
bitmap_obstack_initialize (NULL);
bitmap_initialize (&generic_head, &bitmap_default_obstack);
@@ -16292,7 +16296,7 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
}
else if (bitmap_bit_p (&aligned_head, DECL_UID (t)))
{
- warning_at (OMP_CLAUSE_LOCATION (c), 0,
+ warning_at (OMP_CLAUSE_LOCATION (c), OPT_Wopenmp,
"%qE appears more than once in %<allocate%> clauses",
t);
remove = true;
@@ -16339,6 +16343,8 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
}
gcc_unreachable ();
case OMP_CLAUSE_DEPEND:
+ depend_clause = c;
+ /* FALLTHRU */
case OMP_CLAUSE_AFFINITY:
t = OMP_CLAUSE_DECL (c);
if (TREE_CODE (t) == TREE_LIST
@@ -17071,6 +17077,32 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
}
break;
+ case OMP_CLAUSE_INIT:
+ init_seen = true;
+ if (!OMP_CLAUSE_INIT_TARGETSYNC (c))
+ init_no_targetsync_clause = c;
+ /* FALLTHRU */
+ case OMP_CLAUSE_DESTROY:
+ case OMP_CLAUSE_USE:
+ init_use_destroy_seen = true;
+ t = OMP_CLAUSE_DECL (c);
+ if (bitmap_bit_p (&generic_head, DECL_UID (t)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD appears more than once in action clauses", t);
+ remove = true;
+ }
+ else if (/* ort == C_ORT_OMP_INTEROP [uncomment for depobj init] */
+ !c_omp_interop_t_p (TREE_TYPE (OMP_CLAUSE_DECL (c))))
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD must be of %<omp_interop_t%>", OMP_CLAUSE_DECL (c));
+ else if (OMP_CLAUSE_CODE (c) != OMP_CLAUSE_USE
+ && TREE_READONLY (OMP_CLAUSE_DECL (c)))
+ error_at (OMP_CLAUSE_LOCATION (c),
+ "%qD shall not be const", OMP_CLAUSE_DECL (c));
+ bitmap_set_bit (&generic_head, DECL_UID (t));
+ pc = &OMP_CLAUSE_CHAIN (c);
+ break;
default:
gcc_unreachable ();
}
@@ -17342,6 +17374,19 @@ c_finish_omp_clauses (tree clauses, enum c_omp_region_type ort)
}
}
+ if (ort == C_ORT_OMP_INTEROP
+ && depend_clause
+ && (!init_use_destroy_seen
+ || (init_seen && init_no_targetsync_clause)))
+ {
+ error_at (OMP_CLAUSE_LOCATION (depend_clause),
+ "%<depend%> clause requires action clauses with "
+ "%<targetsync%> interop-type");
+ if (init_no_targetsync_clause)
+ inform (OMP_CLAUSE_LOCATION (init_no_targetsync_clause),
+ "%<init%> clause lacks the %<targetsync%> modifier");
+ }
+
bitmap_obstack_release (NULL);
return clauses;
}