diff options
author | Tobias Burnus <tburnus@baylibre.com> | 2024-11-22 15:30:53 +0100 |
---|---|---|
committer | Tobias Burnus <tburnus@baylibre.com> | 2024-11-22 15:30:53 +0100 |
commit | 8f0c8e577a56891fa104c818834ddafe268722bb (patch) | |
tree | b23eca9aa95f8ff60434daabf5c57a08baf953dd /gcc/c | |
parent | 8d7f2d53c81970c50a4b9bc592ce360563ae192b (diff) | |
download | gcc-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.cc | 437 | ||||
-rw-r--r-- | gcc/c/c-typeck.cc | 47 |
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; } |