aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran/openmp.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran/openmp.cc')
-rw-r--r--gcc/fortran/openmp.cc894
1 files changed, 579 insertions, 315 deletions
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index 905980a..abc27d5 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -59,6 +59,7 @@ struct gfc_omp_directive {
and "nothing". */
static const struct gfc_omp_directive gfc_omp_directives[] = {
+ /* allocate as alias for allocators is also executive. */
{"allocate", GFC_OMP_DIR_DECLARATIVE, ST_OMP_ALLOCATE},
{"allocators", GFC_OMP_DIR_EXECUTABLE, ST_OMP_ALLOCATORS},
{"assumes", GFC_OMP_DIR_INFORMATIONAL, ST_OMP_ASSUMES},
@@ -68,6 +69,7 @@ static const struct gfc_omp_directive gfc_omp_directives[] = {
{"cancellation point", GFC_OMP_DIR_EXECUTABLE, ST_OMP_CANCELLATION_POINT},
{"cancel", GFC_OMP_DIR_EXECUTABLE, ST_OMP_CANCEL},
{"critical", GFC_OMP_DIR_EXECUTABLE, ST_OMP_CRITICAL},
+ /* {"declare induction", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_INDUCTION}, */
/* {"declare mapper", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_MAPPER}, */
{"declare reduction", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_REDUCTION},
{"declare simd", GFC_OMP_DIR_DECLARATIVE, ST_OMP_DECLARE_SIMD},
@@ -79,7 +81,11 @@ static const struct gfc_omp_directive gfc_omp_directives[] = {
{"do", GFC_OMP_DIR_EXECUTABLE, ST_OMP_DO},
/* "error" becomes GFC_OMP_DIR_EXECUTABLE with at(execution) */
{"error", GFC_OMP_DIR_UTILITY, ST_OMP_ERROR},
+ /* {"flatten", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLATTEN}, */
{"flush", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLUSH},
+ /* {"fuse", GFC_OMP_DIR_EXECUTABLE, ST_OMP_FLUSE}, */
+ {"groupprivate", GFC_OMP_DIR_DECLARATIVE, ST_OMP_GROUPPRIVATE},
+ /* {"interchange", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTERCHANGE}, */
{"interop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_INTEROP},
{"loop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_LOOP},
{"masked", GFC_OMP_DIR_EXECUTABLE, ST_OMP_MASKED},
@@ -98,11 +104,15 @@ static const struct gfc_omp_directive gfc_omp_directives[] = {
{"section", GFC_OMP_DIR_SUBSIDIARY, ST_OMP_SECTION},
{"simd", GFC_OMP_DIR_EXECUTABLE, ST_OMP_SIMD},
{"single", GFC_OMP_DIR_EXECUTABLE, ST_OMP_SINGLE},
+ /* {"split", GFC_OMP_DIR_EXECUTABLE, ST_OMP_SPLIT}, */
+ /* {"strip", GFC_OMP_DIR_EXECUTABLE, ST_OMP_STRIP}, */
{"target data", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET_DATA},
{"target enter data", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET_ENTER_DATA},
{"target exit data", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET_EXIT_DATA},
{"target update", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET_UPDATE},
{"target", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TARGET},
+ /* {"taskgraph", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASKGRAPH}, */
+ /* {"task iteration", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASK_ITERATION}, */
{"taskloop", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASKLOOP},
{"taskwait", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASKWAIT},
{"taskyield", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TASKYIELD},
@@ -111,6 +121,7 @@ static const struct gfc_omp_directive gfc_omp_directives[] = {
{"threadprivate", GFC_OMP_DIR_DECLARATIVE, ST_OMP_THREADPRIVATE},
{"tile", GFC_OMP_DIR_EXECUTABLE, ST_OMP_TILE},
{"unroll", GFC_OMP_DIR_EXECUTABLE, ST_OMP_UNROLL},
+ /* {"workdistribute", GFC_OMP_DIR_EXECUTABLE, ST_OMP_WORKDISTRIBUTE}, */
{"workshare", GFC_OMP_DIR_EXECUTABLE, ST_OMP_WORKSHARE},
};
@@ -185,6 +196,7 @@ gfc_free_omp_clauses (gfc_omp_clauses *c)
gfc_free_expr (c->num_teams_lower);
gfc_free_expr (c->num_teams_upper);
gfc_free_expr (c->device);
+ gfc_free_expr (c->dyn_groupprivate);
gfc_free_expr (c->thread_limit);
gfc_free_expr (c->dist_chunk_size);
gfc_free_expr (c->grainsize);
@@ -1162,6 +1174,8 @@ enum omp_mask2
OMP_CLAUSE_NOVARIANTS, /* OpenMP 5.1 */
OMP_CLAUSE_NOCONTEXT, /* OpenMP 5.1 */
OMP_CLAUSE_INTEROP, /* OpenMP 5.1 */
+ OMP_CLAUSE_LOCAL, /* OpenMP 6.0 */
+ OMP_CLAUSE_DYN_GROUPPRIVATE, /* OpenMP 6.1 */
/* This must come last. */
OMP_MASK2_LAST
};
@@ -1588,7 +1602,7 @@ gfc_match_omp_clause_reduction (char pc, gfc_omp_clauses *c, bool openacc,
{
gfc_omp_namelist *p = gfc_get_omp_namelist (), **tl;
p->sym = n->sym;
- p->where = p->where;
+ p->where = n->where;
p->u.map.op = OMP_MAP_ALWAYS_TOFROM;
tl = &c->lists[OMP_LIST_MAP];
@@ -2138,10 +2152,8 @@ gfc_match_omp_prefer_type (char **type_str, int *type_str_len)
the 'interop' directive and the 'append_args' directive of 'declare variant'.
[prefer_type(...)][,][<target|targetsync>, ...])
- If is_init_clause, there might be no modifiers but variables like 'target';
- additionally, the modifier parsing ends with a ':'.
- If not is_init_clause (i.e. append_args), there must be modifiers and the
- parsing ends with ')'. */
+ If is_init_clause, the modifier parsing ends with a ':'.
+ If not is_init_clause (i.e. append_args), the parsing ends with ')'. */
static match
gfc_parser_omp_clause_init_modifiers (bool &target, bool &targetsync,
@@ -2153,9 +2165,10 @@ gfc_parser_omp_clause_init_modifiers (bool &target, bool &targetsync,
*type_str = NULL;
type_str_len = 0;
match m;
- locus old_loc = gfc_current_locus;
- do {
- if (gfc_match ("prefer_type ( ") == MATCH_YES)
+
+ do
+ {
+ if (gfc_match ("prefer_type ( ") == MATCH_YES)
{
if (*type_str)
{
@@ -2181,12 +2194,17 @@ gfc_parser_omp_clause_init_modifiers (bool &target, bool &targetsync,
}
return MATCH_ERROR;
}
- if (gfc_match ("targetsync ") == MATCH_YES)
+
+ if (gfc_match ("prefer_type ") == MATCH_YES)
+ {
+ gfc_error ("Expected %<(%> after %<prefer_type%> at %C");
+ return MATCH_ERROR;
+ }
+
+ if (gfc_match ("targetsync ") == MATCH_YES)
{
if (targetsync)
{
- /* Avoid the word 'modifier' as it could be also be no clauses and
- twice a variable named 'targetsync', which is also invalid. */
gfc_error ("Duplicate %<targetsync%> at %C");
return MATCH_ERROR;
}
@@ -2202,13 +2220,6 @@ gfc_parser_omp_clause_init_modifiers (bool &target, bool &targetsync,
}
if (gfc_match (": ") == MATCH_YES)
break;
- gfc_char_t c = gfc_peek_char ();
- if (!*type_str && (c == ')' || (gfc_current_form != FORM_FREE
- && (c == '_' || ISALPHA (c)))))
- {
- gfc_current_locus = old_loc;
- break;
- }
gfc_error ("Expected %<,%> or %<:%> at %C");
return MATCH_ERROR;
}
@@ -2231,25 +2242,21 @@ gfc_parser_omp_clause_init_modifiers (bool &target, bool &targetsync,
}
if (gfc_match (": ") == MATCH_YES)
break;
- gfc_char_t c = gfc_peek_char ();
- if (!*type_str && (c == ')' || (gfc_current_form != FORM_FREE
- && (c == '_' || ISALPHA (c)))))
- {
- gfc_current_locus = old_loc;
- break;
- }
gfc_error ("Expected %<,%> or %<:%> at %C");
return MATCH_ERROR;
}
- if (*type_str)
- {
- gfc_error ("Expected %<target%> or %<targetsync%> at %C");
- return MATCH_ERROR;
- }
- gfc_current_locus = old_loc;
- break;
+ gfc_error ("Expected %<prefer_type%>, %<target%>, or %<targetsync%> "
+ "at %C");
+ return MATCH_ERROR;
}
while (true);
+
+ if (!target && !targetsync)
+ {
+ gfc_error ("Missing required %<target%> and/or %<targetsync%> "
+ "modifier at %C");
+ return MATCH_ERROR;
+ }
return MATCH_YES;
}
@@ -2266,17 +2273,17 @@ gfc_match_omp_init (gfc_omp_namelist **list)
type_str_len, true) == MATCH_ERROR)
return MATCH_ERROR;
- gfc_omp_namelist **head = NULL;
- if (gfc_match_omp_variable_list ("", list, false, NULL, &head) != MATCH_YES)
- return MATCH_ERROR;
- for (gfc_omp_namelist *n = *head; n; n = n->next)
- {
- n->u.init.target = target;
- n->u.init.targetsync = targetsync;
- n->u.init.len = type_str_len;
- n->u2.init_interop = type_str;
- }
- return MATCH_YES;
+ gfc_omp_namelist **head = NULL;
+ if (gfc_match_omp_variable_list ("", list, false, NULL, &head) != MATCH_YES)
+ return MATCH_ERROR;
+ for (gfc_omp_namelist *n = *head; n; n = n->next)
+ {
+ n->u.init.target = target;
+ n->u.init.targetsync = targetsync;
+ n->u.init.len = type_str_len;
+ n->u2.init_interop = type_str;
+ }
+ return MATCH_YES;
}
@@ -3093,6 +3100,22 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
else
continue;
}
+ if ((mask & OMP_CLAUSE_DYN_GROUPPRIVATE)
+ && gfc_match_dupl_check (!c->dyn_groupprivate,
+ "dyn_groupprivate", true) == MATCH_YES)
+ {
+ if (gfc_match ("fallback ( abort ) : ") == MATCH_YES)
+ c->fallback = OMP_FALLBACK_ABORT;
+ else if (gfc_match ("fallback ( default_mem ) : ") == MATCH_YES)
+ c->fallback = OMP_FALLBACK_DEFAULT_MEM;
+ else if (gfc_match ("fallback ( null ) : ") == MATCH_YES)
+ c->fallback = OMP_FALLBACK_NULL;
+ if (gfc_match_expr (&c->dyn_groupprivate) != MATCH_YES)
+ return MATCH_ERROR;
+ if (gfc_match (" )") != MATCH_YES)
+ goto error;
+ continue;
+ }
break;
case 'e':
if ((mask & OMP_CLAUSE_ENTER))
@@ -3564,6 +3587,10 @@ gfc_match_omp_clauses (gfc_omp_clauses **cp, const omp_mask mask,
&c->lists[OMP_LIST_LINK])
== MATCH_YES))
continue;
+ if ((mask & OMP_CLAUSE_LOCAL)
+ && (gfc_match_omp_to_link ("local (", &c->lists[OMP_LIST_LOCAL])
+ == MATCH_YES))
+ continue;
break;
case 'm':
if ((mask & OMP_CLAUSE_MAP)
@@ -4481,7 +4508,7 @@ error:
| OMP_CLAUSE_COPYOUT | OMP_CLAUSE_DELETE | OMP_CLAUSE_FINALIZE \
| OMP_CLAUSE_DETACH)
#define OACC_WAIT_CLAUSES \
- omp_mask (OMP_CLAUSE_ASYNC)
+ omp_mask (OMP_CLAUSE_ASYNC) | OMP_CLAUSE_IF
#define OACC_ROUTINE_CLAUSES \
(omp_mask (OMP_CLAUSE_GANG) | OMP_CLAUSE_WORKER | OMP_CLAUSE_VECTOR \
| OMP_CLAUSE_SEQ \
@@ -5061,7 +5088,8 @@ cleanup:
| OMP_CLAUSE_FIRSTPRIVATE | OMP_CLAUSE_DEFAULTMAP \
| OMP_CLAUSE_IS_DEVICE_PTR | OMP_CLAUSE_IN_REDUCTION \
| OMP_CLAUSE_THREAD_LIMIT | OMP_CLAUSE_ALLOCATE \
- | OMP_CLAUSE_HAS_DEVICE_ADDR | OMP_CLAUSE_USES_ALLOCATORS)
+ | OMP_CLAUSE_HAS_DEVICE_ADDR | OMP_CLAUSE_USES_ALLOCATORS \
+ | OMP_CLAUSE_DYN_GROUPPRIVATE)
#define OMP_TARGET_DATA_CLAUSES \
(omp_mask (OMP_CLAUSE_DEVICE) | OMP_CLAUSE_MAP | OMP_CLAUSE_IF \
| OMP_CLAUSE_USE_DEVICE_PTR | OMP_CLAUSE_USE_DEVICE_ADDR)
@@ -5089,7 +5117,7 @@ cleanup:
(omp_mask (OMP_CLAUSE_THREADS) | OMP_CLAUSE_SIMD)
#define OMP_DECLARE_TARGET_CLAUSES \
(omp_mask (OMP_CLAUSE_ENTER) | OMP_CLAUSE_LINK | OMP_CLAUSE_DEVICE_TYPE \
- | OMP_CLAUSE_TO | OMP_CLAUSE_INDIRECT)
+ | OMP_CLAUSE_TO | OMP_CLAUSE_INDIRECT | OMP_CLAUSE_LOCAL)
#define OMP_ATOMIC_CLAUSES \
(omp_mask (OMP_CLAUSE_ATOMIC) | OMP_CLAUSE_CAPTURE | OMP_CLAUSE_HINT \
| OMP_CLAUSE_MEMORDER | OMP_CLAUSE_COMPARE | OMP_CLAUSE_FAIL \
@@ -6110,7 +6138,7 @@ gfc_match_omp_declare_target (void)
gfc_buffer_error (false);
static const int to_enter_link_lists[]
- = { OMP_LIST_TO, OMP_LIST_ENTER, OMP_LIST_LINK };
+ = { OMP_LIST_TO, OMP_LIST_ENTER, OMP_LIST_LINK, OMP_LIST_LOCAL };
for (size_t listn = 0; listn < ARRAY_SIZE (to_enter_link_lists)
&& (list = to_enter_link_lists[listn], true); ++listn)
for (n = c->lists[list]; n; n = n->next)
@@ -6119,6 +6147,8 @@ gfc_match_omp_declare_target (void)
else if (n->u.common->head)
n->u.common->head->mark = 0;
+ if (c->device_type == OMP_DEVICE_TYPE_UNSET)
+ c->device_type = OMP_DEVICE_TYPE_ANY;
for (size_t listn = 0; listn < ARRAY_SIZE (to_enter_link_lists)
&& (list = to_enter_link_lists[listn], true); ++listn)
for (n = c->lists[list]; n; n = n->next)
@@ -6127,105 +6157,161 @@ gfc_match_omp_declare_target (void)
if (n->sym->attr.in_common)
gfc_error_now ("OMP DECLARE TARGET variable at %L is an "
"element of a COMMON block", &n->where);
+ else if (n->sym->attr.omp_groupprivate && list != OMP_LIST_LOCAL)
+ gfc_error_now ("List item %qs at %L not appear in the %qs clause "
+ "as it was previously specified in a GROUPPRIVATE "
+ "directive", n->sym->name, &n->where,
+ list == OMP_LIST_LINK
+ ? "link" : list == OMP_LIST_TO ? "to" : "enter");
else if (n->sym->mark)
gfc_error_now ("Variable at %L mentioned multiple times in "
"clauses of the same OMP DECLARE TARGET directive",
&n->where);
- else if (n->sym->attr.omp_declare_target
- && n->sym->attr.omp_declare_target_link
- && list != OMP_LIST_LINK)
+ else if ((n->sym->attr.omp_declare_target_link
+ || n->sym->attr.omp_declare_target_local)
+ && list != OMP_LIST_LINK
+ && list != OMP_LIST_LOCAL)
gfc_error_now ("OMP DECLARE TARGET variable at %L previously "
- "mentioned in LINK clause and later in %s clause",
- &n->where, list == OMP_LIST_TO ? "TO" : "ENTER");
+ "mentioned in %s clause and later in %s clause",
+ &n->where,
+ n->sym->attr.omp_declare_target_link ? "LINK"
+ : "LOCAL",
+ list == OMP_LIST_TO ? "TO" : "ENTER");
else if (n->sym->attr.omp_declare_target
- && !n->sym->attr.omp_declare_target_link
- && list == OMP_LIST_LINK)
+ && (list == OMP_LIST_LINK || list == OMP_LIST_LOCAL))
gfc_error_now ("OMP DECLARE TARGET variable at %L previously "
"mentioned in TO or ENTER clause and later in "
- "LINK clause", &n->where);
- else if (gfc_add_omp_declare_target (&n->sym->attr, n->sym->name,
- &n->sym->declared_at))
+ "%s clause", &n->where,
+ list == OMP_LIST_LINK ? "LINK" : "LOCAL");
+ else
{
+ if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+ gfc_add_omp_declare_target (&n->sym->attr, n->sym->name,
+ &n->sym->declared_at);
if (list == OMP_LIST_LINK)
gfc_add_omp_declare_target_link (&n->sym->attr, n->sym->name,
&n->sym->declared_at);
+ if (list == OMP_LIST_LOCAL)
+ gfc_add_omp_declare_target_local (&n->sym->attr, n->sym->name,
+ &n->sym->declared_at);
+ }
+ if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
+ && n->sym->attr.omp_device_type != c->device_type)
+ {
+ const char *dt = "any";
+ if (n->sym->attr.omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+ dt = "nohost";
+ else if (n->sym->attr.omp_device_type == OMP_DEVICE_TYPE_HOST)
+ dt = "host";
+ if (n->sym->attr.omp_groupprivate)
+ gfc_error_now ("List item %qs at %L set in previous OMP "
+ "GROUPPRIVATE directive to the different "
+ "DEVICE_TYPE %qs", n->sym->name, &n->where, dt);
+ else
+ gfc_error_now ("List item %qs at %L set in previous OMP "
+ "DECLARE TARGET directive to the different "
+ "DEVICE_TYPE %qs", n->sym->name, &n->where, dt);
}
- if (c->device_type != OMP_DEVICE_TYPE_UNSET)
- {
- if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
- && n->sym->attr.omp_device_type != c->device_type)
- gfc_error_now ("List item %qs at %L set in previous OMP DECLARE "
- "TARGET directive to a different DEVICE_TYPE",
- n->sym->name, &n->where);
- n->sym->attr.omp_device_type = c->device_type;
- }
- if (c->indirect)
+ n->sym->attr.omp_device_type = c->device_type;
+ if (c->indirect && c->device_type != OMP_DEVICE_TYPE_ANY)
{
- if (n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
- && n->sym->attr.omp_device_type != OMP_DEVICE_TYPE_ANY)
- gfc_error_now ("DEVICE_TYPE must be ANY when used with "
- "INDIRECT at %L", &n->where);
- n->sym->attr.omp_declare_target_indirect = c->indirect;
+ gfc_error_now ("DEVICE_TYPE must be ANY when used with INDIRECT "
+ "at %L", &n->where);
+ c->indirect = 0;
}
-
+ n->sym->attr.omp_declare_target_indirect = c->indirect;
+ if (list == OMP_LIST_LINK && c->device_type == OMP_DEVICE_TYPE_NOHOST)
+ gfc_error_now ("List item %qs at %L set with NOHOST specified may "
+ "not appear in a LINK clause", n->sym->name,
+ &n->where);
n->sym->mark = 1;
}
- else if (n->u.common->omp_declare_target
- && n->u.common->omp_declare_target_link
- && list != OMP_LIST_LINK)
- gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously "
- "mentioned in LINK clause and later in %s clause",
- &n->where, list == OMP_LIST_TO ? "TO" : "ENTER");
- else if (n->u.common->omp_declare_target
- && !n->u.common->omp_declare_target_link
- && list == OMP_LIST_LINK)
- gfc_error_now ("OMP DECLARE TARGET COMMON at %L previously "
- "mentioned in TO or ENTER clause and later in "
- "LINK clause", &n->where);
- else if (n->u.common->head && n->u.common->head->mark)
- gfc_error_now ("COMMON at %L mentioned multiple times in "
- "clauses of the same OMP DECLARE TARGET directive",
- &n->where);
- else
- {
- n->u.common->omp_declare_target = 1;
- n->u.common->omp_declare_target_link = (list == OMP_LIST_LINK);
+ else /* common block */
+ {
+ if (n->u.common->omp_groupprivate && list != OMP_LIST_LOCAL)
+ gfc_error_now ("Common block %</%s/%> at %L not appear in the %qs "
+ "clause as it was previously specified in a "
+ "GROUPPRIVATE directive",
+ n->u.common->name, &n->where,
+ list == OMP_LIST_LINK
+ ? "link" : list == OMP_LIST_TO ? "to" : "enter");
+ else if (n->u.common->head && n->u.common->head->mark)
+ gfc_error_now ("Common block %</%s/%> at %L mentioned multiple "
+ "times in clauses of the same OMP DECLARE TARGET "
+ "directive", n->u.common->name, &n->where);
+ else if ((n->u.common->omp_declare_target_link
+ || n->u.common->omp_declare_target_local)
+ && list != OMP_LIST_LINK
+ && list != OMP_LIST_LOCAL)
+ gfc_error_now ("Common block %</%s/%> at %L previously mentioned "
+ "in %s clause and later in %s clause",
+ n->u.common->name, &n->where,
+ n->u.common->omp_declare_target_link ? "LINK"
+ : "LOCAL",
+ list == OMP_LIST_TO ? "TO" : "ENTER");
+ else if (n->u.common->omp_declare_target
+ && (list == OMP_LIST_LINK || list == OMP_LIST_LOCAL))
+ gfc_error_now ("Common block %</%s/%> at %L previously mentioned "
+ "in TO or ENTER clause and later in %s clause",
+ n->u.common->name, &n->where,
+ list == OMP_LIST_LINK ? "LINK" : "LOCAL");
if (n->u.common->omp_device_type != OMP_DEVICE_TYPE_UNSET
&& n->u.common->omp_device_type != c->device_type)
- gfc_error_now ("COMMON at %L set in previous OMP DECLARE "
- "TARGET directive to a different DEVICE_TYPE",
- &n->where);
+ {
+ const char *dt = "any";
+ if (n->u.common->omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+ dt = "nohost";
+ else if (n->u.common->omp_device_type == OMP_DEVICE_TYPE_HOST)
+ dt = "host";
+ if (n->u.common->omp_groupprivate)
+ gfc_error_now ("Common block %</%s/%> at %L set in previous OMP "
+ "GROUPPRIVATE directive to the different "
+ "DEVICE_TYPE %qs", n->u.common->name, &n->where,
+ dt);
+ else
+ gfc_error_now ("Common block %</%s/%> at %L set in previous OMP "
+ "DECLARE TARGET directive to the different "
+ "DEVICE_TYPE %qs", n->u.common->name, &n->where,
+ dt);
+ }
n->u.common->omp_device_type = c->device_type;
+ if (c->indirect && c->device_type != OMP_DEVICE_TYPE_ANY)
+ {
+ gfc_error_now ("DEVICE_TYPE must be ANY when used with INDIRECT "
+ "at %L", &n->where);
+ c->indirect = 0;
+ }
+ if (list == OMP_LIST_LINK && c->device_type == OMP_DEVICE_TYPE_NOHOST)
+ gfc_error_now ("Common block %</%s/%> at %L set with NOHOST "
+ "specified may not appear in a LINK clause",
+ n->u.common->name, &n->where);
+
+ if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+ n->u.common->omp_declare_target = 1;
+ if (list == OMP_LIST_LINK)
+ n->u.common->omp_declare_target_link = 1;
+ if (list == OMP_LIST_LOCAL)
+ n->u.common->omp_declare_target_local = 1;
+
for (s = n->u.common->head; s; s = s->common_next)
{
s->mark = 1;
- if (gfc_add_omp_declare_target (&s->attr, s->name,
- &s->declared_at))
- {
- if (list == OMP_LIST_LINK)
- gfc_add_omp_declare_target_link (&s->attr, s->name,
- &s->declared_at);
- }
- if (s->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
- && s->attr.omp_device_type != c->device_type)
- gfc_error_now ("List item %qs at %L set in previous OMP DECLARE"
- " TARGET directive to a different DEVICE_TYPE",
- s->name, &n->where);
+ if (list == OMP_LIST_TO || list == OMP_LIST_ENTER)
+ gfc_add_omp_declare_target (&s->attr, s->name, &n->where);
+ if (list == OMP_LIST_LINK)
+ gfc_add_omp_declare_target_link (&s->attr, s->name, &n->where);
+ if (list == OMP_LIST_LOCAL)
+ gfc_add_omp_declare_target_local (&s->attr, s->name, &n->where);
s->attr.omp_device_type = c->device_type;
-
- if (c->indirect
- && s->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
- && s->attr.omp_device_type != OMP_DEVICE_TYPE_ANY)
- gfc_error_now ("DEVICE_TYPE must be ANY when used with "
- "INDIRECT at %L", &n->where);
s->attr.omp_declare_target_indirect = c->indirect;
}
}
if ((c->device_type || c->indirect)
&& !c->lists[OMP_LIST_ENTER]
&& !c->lists[OMP_LIST_TO]
- && !c->lists[OMP_LIST_LINK])
+ && !c->lists[OMP_LIST_LINK]
+ && !c->lists[OMP_LIST_LOCAL])
gfc_warning_now (OPT_Wopenmp,
"OMP DECLARE TARGET directive at %L with only "
"DEVICE_TYPE or INDIRECT clauses is ignored",
@@ -6313,9 +6399,8 @@ gfc_match_omp_interop (void)
trait-score:
score(score-expression) */
-match
-gfc_match_omp_context_selector (gfc_omp_set_selector *oss,
- bool metadirective_p)
+static match
+gfc_match_omp_context_selector (gfc_omp_set_selector *oss)
{
do
{
@@ -6379,22 +6464,8 @@ gfc_match_omp_context_selector (gfc_omp_set_selector *oss,
gfc_error ("expected %<(%> at %C");
return MATCH_ERROR;
}
- if (gfc_match_expr (&os->score) != MATCH_YES
- || !gfc_resolve_expr (os->score)
- || os->score->ts.type != BT_INTEGER
- || os->score->rank != 0)
- {
- gfc_error ("%<score%> argument must be constant integer "
- "expression at %C");
- return MATCH_ERROR;
- }
-
- if (os->score->expr_type == EXPR_CONSTANT
- && mpz_sgn (os->score->value.integer) < 0)
- {
- gfc_error ("%<score%> argument must be non-negative at %C");
- return MATCH_ERROR;
- }
+ if (gfc_match_expr (&os->score) != MATCH_YES)
+ return MATCH_ERROR;
if (gfc_match (" )") != MATCH_YES)
{
@@ -6427,6 +6498,8 @@ gfc_match_omp_context_selector (gfc_omp_set_selector *oss,
else
{
gfc_error ("expected identifier at %C");
+ free (otp);
+ os->properties = nullptr;
return MATCH_ERROR;
}
}
@@ -6447,6 +6520,8 @@ gfc_match_omp_context_selector (gfc_omp_set_selector *oss,
{
gfc_error ("expected identifier or string literal "
"at %C");
+ free (otp);
+ os->properties = nullptr;
return MATCH_ERROR;
}
@@ -6467,51 +6542,8 @@ gfc_match_omp_context_selector (gfc_omp_set_selector *oss,
if (gfc_match_expr (&otp->expr) != MATCH_YES)
{
gfc_error ("expected expression at %C");
- return MATCH_ERROR;
- }
- if (!gfc_resolve_expr (otp->expr)
- || (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR
- && otp->expr->ts.type != BT_LOGICAL)
- || (property_kind == OMP_TRAIT_PROPERTY_DEV_NUM_EXPR
- && otp->expr->ts.type != BT_INTEGER)
- || otp->expr->rank != 0
- || (!metadirective_p
- && otp->expr->expr_type != EXPR_CONSTANT))
- {
- if (metadirective_p)
- {
- if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
- gfc_error ("property must be a "
- "logical expression at %L",
- &otp->expr->where);
- else
- gfc_error ("property must be an "
- "integer expression at %L",
- &otp->expr->where);
- }
- else
- {
- if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
- gfc_error ("property must be a constant "
- "logical expression at %L",
- &otp->expr->where);
- else
- gfc_error ("property must be a constant "
- "integer expression at %L",
- &otp->expr->where);
- }
- return MATCH_ERROR;
- }
- /* Device number must be conforming, which includes
- omp_initial_device (-1) and omp_invalid_device (-4). */
- if (property_kind == OMP_TRAIT_PROPERTY_DEV_NUM_EXPR
- && otp->expr->expr_type == EXPR_CONSTANT
- && mpz_sgn (otp->expr->value.integer) < 0
- && mpz_cmp_si (otp->expr->value.integer, -1) != 0
- && mpz_cmp_si (otp->expr->value.integer, -4) != 0)
- {
- gfc_error ("property must be a conforming device number "
- "at %C");
+ free (otp);
+ os->properties = nullptr;
return MATCH_ERROR;
}
break;
@@ -6587,9 +6619,8 @@ gfc_match_omp_context_selector (gfc_omp_set_selector *oss,
implementation
user */
-match
-gfc_match_omp_context_selector_specification (gfc_omp_set_selector **oss_head,
- bool metadirective_p)
+static match
+gfc_match_omp_context_selector_specification (gfc_omp_set_selector **oss_head)
{
do
{
@@ -6626,7 +6657,7 @@ gfc_match_omp_context_selector_specification (gfc_omp_set_selector **oss_head,
oss->code = set;
*oss_head = oss;
- if (gfc_match_omp_context_selector (oss, metadirective_p) != MATCH_YES)
+ if (gfc_match_omp_context_selector (oss) != MATCH_YES)
return MATCH_ERROR;
m = gfc_match (" }");
@@ -6757,8 +6788,7 @@ gfc_match_omp_declare_variant (void)
return MATCH_ERROR;
}
has_match = true;
- if (gfc_match_omp_context_selector_specification (&odv->set_selectors,
- false)
+ if (gfc_match_omp_context_selector_specification (&odv->set_selectors)
!= MATCH_YES)
return MATCH_ERROR;
if (gfc_match (" )") != MATCH_YES)
@@ -6989,13 +7019,9 @@ gfc_match_omp_declare_variant (void)
return MATCH_ERROR;
}
- if ((has_adjust_args || has_append_args) && !has_match)
+ if (!has_match)
{
- gfc_error ("the %qs clause at %L can only be specified if the "
- "%<dispatch%> selector of the construct selector set appears "
- "in the %<match%> clause",
- has_adjust_args ? "adjust_args" : "append_args",
- has_adjust_args ? &adjust_args_loc : &append_args_loc);
+ gfc_error ("expected %<match%> clause at %C");
return MATCH_ERROR;
}
@@ -7053,7 +7079,7 @@ match_omp_metadirective (bool begin_p)
if (!default_p)
{
- if (gfc_match_omp_context_selector_specification (&selectors, true)
+ if (gfc_match_omp_context_selector_specification (&selectors)
!= MATCH_YES)
return MATCH_ERROR;
@@ -7165,32 +7191,44 @@ gfc_match_omp_metadirective (void)
return match_omp_metadirective (false);
}
-match
-gfc_match_omp_threadprivate (void)
+/* Match 'omp threadprivate' or 'omp groupprivate'. */
+static match
+gfc_match_omp_thread_group_private (bool is_groupprivate)
{
locus old_loc;
char n[GFC_MAX_SYMBOL_LEN+1];
gfc_symbol *sym;
match m;
gfc_symtree *st;
+ struct sym_loc_t { gfc_symbol *sym; gfc_common_head *com; locus loc; };
+ auto_vec<sym_loc_t> syms;
old_loc = gfc_current_locus;
- m = gfc_match (" (");
+ m = gfc_match (" ( ");
if (m != MATCH_YES)
return m;
for (;;)
{
+ locus sym_loc = gfc_current_locus;
m = gfc_match_symbol (&sym, 0);
switch (m)
{
case MATCH_YES:
if (sym->attr.in_common)
- gfc_error_now ("Threadprivate variable at %C is an element of "
- "a COMMON block");
- else if (!gfc_add_threadprivate (&sym->attr, sym->name, &sym->declared_at))
+ gfc_error_now ("%qs variable at %L is an element of a COMMON block",
+ is_groupprivate ? "groupprivate" : "threadprivate",
+ &sym_loc);
+ else if (!is_groupprivate
+ && !gfc_add_threadprivate (&sym->attr, sym->name, &sym_loc))
goto cleanup;
+ else if (is_groupprivate)
+ {
+ if (!gfc_add_omp_groupprivate (&sym->attr, sym->name, &sym_loc))
+ goto cleanup;
+ syms.safe_push ({sym, nullptr, sym_loc});
+ }
goto next_item;
case MATCH_NO:
break;
@@ -7207,12 +7245,20 @@ gfc_match_omp_threadprivate (void)
st = gfc_find_symtree (gfc_current_ns->common_root, n);
if (st == NULL)
{
- gfc_error ("COMMON block /%s/ not found at %C", n);
+ gfc_error ("COMMON block /%s/ not found at %L", n, &sym_loc);
goto cleanup;
}
- st->n.common->threadprivate = 1;
+ syms.safe_push ({nullptr, st->n.common, sym_loc});
+ if (is_groupprivate)
+ st->n.common->omp_groupprivate = 1;
+ else
+ st->n.common->threadprivate = 1;
for (sym = st->n.common->head; sym; sym = sym->common_next)
- if (!gfc_add_threadprivate (&sym->attr, sym->name, &sym->declared_at))
+ if (!is_groupprivate
+ && !gfc_add_threadprivate (&sym->attr, sym->name, &sym_loc))
+ goto cleanup;
+ else if (is_groupprivate
+ && !gfc_add_omp_groupprivate (&sym->attr, sym->name, &sym_loc))
goto cleanup;
next_item:
@@ -7222,16 +7268,89 @@ gfc_match_omp_threadprivate (void)
goto syntax;
}
+ if (is_groupprivate)
+ {
+ gfc_omp_clauses *c;
+ m = gfc_match_omp_clauses (&c, omp_mask (OMP_CLAUSE_DEVICE_TYPE));
+ if (m == MATCH_ERROR)
+ return MATCH_ERROR;
+
+ if (c->device_type == OMP_DEVICE_TYPE_UNSET)
+ c->device_type = OMP_DEVICE_TYPE_ANY;
+
+ for (size_t i = 0; i < syms.length (); i++)
+ if (syms[i].sym)
+ {
+ sym_loc_t &n = syms[i];
+ if (n.sym->attr.in_common)
+ gfc_error_now ("Variable %qs at %L is an element of a COMMON "
+ "block", n.sym->name, &n.loc);
+ else if (n.sym->attr.omp_declare_target
+ || n.sym->attr.omp_declare_target_link)
+ gfc_error_now ("List item %qs at %L implies OMP DECLARE TARGET "
+ "with the LOCAL clause, but it has been specified"
+ " with a different clause before",
+ n.sym->name, &n.loc);
+ if (n.sym->attr.omp_device_type != OMP_DEVICE_TYPE_UNSET
+ && n.sym->attr.omp_device_type != c->device_type)
+ {
+ const char *dt = "any";
+ if (n.sym->attr.omp_device_type == OMP_DEVICE_TYPE_HOST)
+ dt = "host";
+ else if (n.sym->attr.omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+ dt = "nohost";
+ gfc_error_now ("List item %qs at %L set in previous OMP DECLARE "
+ "TARGET directive to the different DEVICE_TYPE %qs",
+ n.sym->name, &n.loc, dt);
+ }
+ gfc_add_omp_declare_target_local (&n.sym->attr, n.sym->name,
+ &n.loc);
+ n.sym->attr.omp_device_type = c->device_type;
+ }
+ else /* Common block. */
+ {
+ sym_loc_t &n = syms[i];
+ if (n.com->omp_declare_target
+ || n.com->omp_declare_target_link)
+ gfc_error_now ("List item %</%s/%> at %L implies OMP DECLARE "
+ "TARGET with the LOCAL clause, but it has been "
+ "specified with a different clause before",
+ n.com->name, &n.loc);
+ if (n.com->omp_device_type != OMP_DEVICE_TYPE_UNSET
+ && n.com->omp_device_type != c->device_type)
+ {
+ const char *dt = "any";
+ if (n.com->omp_device_type == OMP_DEVICE_TYPE_HOST)
+ dt = "host";
+ else if (n.com->omp_device_type == OMP_DEVICE_TYPE_NOHOST)
+ dt = "nohost";
+ gfc_error_now ("List item %qs at %L set in previous OMP DECLARE"
+ " TARGET directive to the different DEVICE_TYPE "
+ "%qs", n.com->name, &n.loc, dt);
+ }
+ n.com->omp_declare_target_local = 1;
+ n.com->omp_device_type = c->device_type;
+ for (gfc_symbol *s = n.com->head; s; s = s->common_next)
+ {
+ gfc_add_omp_declare_target_local (&s->attr, s->name, &n.loc);
+ s->attr.omp_device_type = c->device_type;
+ }
+ }
+ free (c);
+ }
+
if (gfc_match_omp_eos () != MATCH_YES)
{
- gfc_error ("Unexpected junk after OMP THREADPRIVATE at %C");
+ gfc_error ("Unexpected junk after OMP %s at %C",
+ is_groupprivate ? "GROUPPRIVATE" : "THREADPRIVATE");
goto cleanup;
}
return MATCH_YES;
syntax:
- gfc_error ("Syntax error in !$OMP THREADPRIVATE list at %C");
+ gfc_error ("Syntax error in !$OMP %s list at %C",
+ is_groupprivate ? "GROUPPRIVATE" : "THREADPRIVATE");
cleanup:
gfc_current_locus = old_loc;
@@ -7240,6 +7359,20 @@ cleanup:
match
+gfc_match_omp_groupprivate (void)
+{
+ return gfc_match_omp_thread_group_private (true);
+}
+
+
+match
+gfc_match_omp_threadprivate (void)
+{
+ return gfc_match_omp_thread_group_private (false);
+}
+
+
+match
gfc_match_omp_parallel (void)
{
return match_omp (EXEC_OMP_PARALLEL, OMP_PARALLEL_CLAUSES);
@@ -8416,9 +8549,9 @@ resolve_omp_udr_clause (gfc_omp_namelist *n, gfc_namespace *ns,
}
/* Assume that a constant expression in the range 1 (omp_default_mem_alloc)
- to 8 (omp_thread_mem_alloc) range, or 200 (ompx_gnu_pinned_mem_alloc) is
- fine. The original symbol name is already lost during matching via
- gfc_match_expr. */
+ to GOMP_OMP_PREDEF_ALLOC_MAX, or GOMP_OMPX_PREDEF_ALLOC_MIN to
+ GOMP_OMPX_PREDEF_ALLOC_MAX is fine. The original symbol name is already
+ lost during matching via gfc_match_expr. */
static bool
is_predefined_allocator (gfc_expr *expr)
{
@@ -8549,7 +8682,8 @@ gfc_resolve_omp_allocate (gfc_namespace *ns, gfc_omp_namelist *list)
if (n->sym->attr.in_common || n->sym->attr.save || n->sym->ns->save_all
|| (n->sym->ns->proc_name
&& (n->sym->ns->proc_name->attr.flavor == FL_PROGRAM
- || n->sym->ns->proc_name->attr.flavor == FL_MODULE)))
+ || n->sym->ns->proc_name->attr.flavor == FL_MODULE
+ || n->sym->ns->proc_name->attr.flavor == FL_BLOCK_DATA)))
{
bool com = n->sym->attr.in_common;
if (!n->u2.allocator)
@@ -8563,6 +8697,30 @@ gfc_resolve_omp_allocate (gfc_namespace *ns, gfc_omp_namelist *list)
&n->u2.allocator->where, com ? "/" : "",
com ? n->sym->common_head->name : n->sym->name,
com ? "/" : "", &n->where);
+ /* Only local static variables might use omp_cgroup_mem_alloc (6),
+ omp_pteam_mem_alloc (7), or omp_thread_mem_alloc (8). */
+ else if ((!ns->proc_name
+ || ns->proc_name->attr.flavor == FL_PROGRAM
+ || ns->proc_name->attr.flavor == FL_BLOCK_DATA
+ || ns->proc_name->attr.flavor == FL_MODULE
+ || com)
+ && mpz_cmp_si (n->u2.allocator->value.integer,
+ 6 /* cgroup */) >= 0
+ && mpz_cmp_si (n->u2.allocator->value.integer,
+ 8 /* thread */) <= 0)
+ {
+ const char *alloc_name[] = {"omp_cgroup_mem_alloc",
+ "omp_pteam_mem_alloc",
+ "omp_thread_mem_alloc" };
+ gfc_error ("Predefined allocator %qs in ALLOCATOR clause at %L, "
+ "used for list item %<%s%s%s%> at %L, may only be used"
+ " for local static variables",
+ alloc_name[mpz_get_ui (n->u2.allocator->value.integer)
+ - 6 /* cgroup */], &n->u2.allocator->where,
+ com ? "/" : "",
+ com ? n->sym->common_head->name : n->sym->name,
+ com ? "/" : "", &n->where);
+ }
while (n->sym->attr.in_common && n->next && n->next->sym
&& n->sym->common_head == n->next->sym->common_head)
n = n->next;
@@ -8611,7 +8769,7 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
"TO", "FROM", "INCLUSIVE", "EXCLUSIVE",
"REDUCTION", "REDUCTION" /*inscan*/, "REDUCTION" /*task*/,
"IN_REDUCTION", "TASK_REDUCTION",
- "DEVICE_RESIDENT", "LINK", "USE_DEVICE",
+ "DEVICE_RESIDENT", "LINK", "LOCAL", "USE_DEVICE",
"CACHE", "IS_DEVICE_PTR", "USE_DEVICE_PTR", "USE_DEVICE_ADDR",
"NONTEMPORAL", "ALLOCATE", "HAS_DEVICE_ADDR", "ENTER",
"USES_ALLOCATORS", "INIT", "USE", "DESTROY", "INTEROP", "ADJUST_ARGS" };
@@ -8818,6 +8976,9 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
}
if (omp_clauses->num_threads)
resolve_positive_int_expr (omp_clauses->num_threads, "NUM_THREADS");
+ if (omp_clauses->dyn_groupprivate)
+ resolve_nonnegative_int_expr (omp_clauses->dyn_groupprivate,
+ "DYN_GROUPPRIVATE");
if (omp_clauses->chunk_size)
{
gfc_expr *expr = omp_clauses->chunk_size;
@@ -8902,15 +9063,21 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
if (list == OMP_LIST_MAP
&& n->sym->attr.flavor == FL_PARAMETER)
{
+ /* OpenACC since 3.4 permits for Fortran named constants, but
+ permits removing then as optimization is not needed and such
+ ignore them. Likewise below for FIRSTPRIVATE. */
if (openacc)
- gfc_error ("Object %qs is not a variable at %L; parameters"
- " cannot be and need not be copied", n->sym->name,
- &n->where);
+ gfc_warning (OPT_Wsurprising, "Clause for object %qs at %L is "
+ "ignored as parameters need not be copied",
+ n->sym->name, &n->where);
else
gfc_error ("Object %qs is not a variable at %L; parameters"
" cannot be and need not be mapped", n->sym->name,
&n->where);
}
+ else if (openacc && n->sym->attr.flavor == FL_PARAMETER)
+ gfc_warning (OPT_Wsurprising, "Clause for object %qs at %L is ignored"
+ " as it is a parameter", n->sym->name, &n->where);
else if (list != OMP_LIST_USES_ALLOCATORS)
gfc_error ("Object %qs is not a variable at %L", n->sym->name,
&n->where);
@@ -9688,22 +9855,6 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
&& n->sym->as->type == AS_ASSUMED_SIZE)
gfc_error ("Assumed size array %qs in %s clause at %L",
n->sym->name, name, &n->where);
- if (!openacc
- && list == OMP_LIST_MAP
- && n->sym->ts.type == BT_DERIVED
- && n->sym->ts.u.derived->attr.alloc_comp)
- gfc_error ("List item %qs with allocatable components is not "
- "permitted in map clause at %L", n->sym->name,
- &n->where);
- if (!openacc
- && (list == OMP_LIST_MAP
- || list == OMP_LIST_FROM
- || list == OMP_LIST_TO)
- && ((n->expr && n->expr->ts.type == BT_CLASS)
- || (!n->expr && n->sym->ts.type == BT_CLASS)))
- gfc_warning (OPT_Wopenmp,
- "Mapping polymorphic list item at %L is "
- "unspecified behavior", &n->where);
if (list == OMP_LIST_MAP && !openacc)
switch (code->op)
{
@@ -10015,9 +10166,11 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
n->sym->name, name, &n->where);
if (!openacc
- && list == OMP_LIST_FIRSTPRIVATE
- && ((n->expr && n->expr->ts.type == BT_CLASS)
- || (!n->expr && n->sym->ts.type == BT_CLASS)))
+ && (list == OMP_LIST_PRIVATE
+ || list == OMP_LIST_FIRSTPRIVATE)
+ && ((n->sym->ts.type == BT_DERIVED
+ && n->sym->ts.u.derived->attr.alloc_comp)
+ || n->sym->ts.type == BT_CLASS))
switch (code->op)
{
case EXEC_OMP_TARGET:
@@ -10032,9 +10185,19 @@ resolve_omp_clauses (gfc_code *code, gfc_omp_clauses *omp_clauses,
case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD:
case EXEC_OMP_TARGET_TEAMS_LOOP:
- gfc_warning (OPT_Wopenmp,
- "FIRSTPRIVATE with polymorphic list item at "
- "%L is unspecified behavior", &n->where);
+ if (n->sym->ts.type == BT_DERIVED
+ && n->sym->ts.u.derived->attr.alloc_comp)
+ gfc_error ("Sorry, list item %qs at %L with allocatable"
+ " components is not yet supported in %s "
+ "clause", n->sym->name, &n->where,
+ list == OMP_LIST_PRIVATE ? "PRIVATE"
+ : "FIRSTPRIVATE");
+ else
+ gfc_error ("Polymorphic list item %qs at %L in %s "
+ "clause has unspecified behavior and "
+ "unsupported", n->sym->name, &n->where,
+ list == OMP_LIST_PRIVATE ? "PRIVATE"
+ : "FIRSTPRIVATE");
break;
default:
break;
@@ -11427,82 +11590,10 @@ icode_code_error_callback (gfc_code **codep,
/* Errors have already been diagnosed in match_exit_cycle. */
state->errorp = true;
break;
- case EXEC_OMP_CRITICAL:
- case EXEC_OMP_DO:
- case EXEC_OMP_FLUSH:
- case EXEC_OMP_MASTER:
- case EXEC_OMP_ORDERED:
- case EXEC_OMP_PARALLEL:
- case EXEC_OMP_PARALLEL_DO:
- case EXEC_OMP_PARALLEL_SECTIONS:
- case EXEC_OMP_PARALLEL_WORKSHARE:
- case EXEC_OMP_SECTIONS:
- case EXEC_OMP_SINGLE:
- case EXEC_OMP_WORKSHARE:
- case EXEC_OMP_ATOMIC:
- case EXEC_OMP_BARRIER:
- case EXEC_OMP_END_NOWAIT:
- case EXEC_OMP_END_SINGLE:
- case EXEC_OMP_TASK:
- case EXEC_OMP_TASKWAIT:
- case EXEC_OMP_TASKYIELD:
- case EXEC_OMP_CANCEL:
- case EXEC_OMP_CANCELLATION_POINT:
- case EXEC_OMP_TASKGROUP:
- case EXEC_OMP_SIMD:
- case EXEC_OMP_DO_SIMD:
- case EXEC_OMP_PARALLEL_DO_SIMD:
- case EXEC_OMP_TARGET:
- case EXEC_OMP_TARGET_DATA:
- case EXEC_OMP_TEAMS:
- case EXEC_OMP_DISTRIBUTE:
- case EXEC_OMP_DISTRIBUTE_SIMD:
- case EXEC_OMP_DISTRIBUTE_PARALLEL_DO:
- case EXEC_OMP_DISTRIBUTE_PARALLEL_DO_SIMD:
- case EXEC_OMP_TARGET_TEAMS:
- case EXEC_OMP_TEAMS_DISTRIBUTE:
- case EXEC_OMP_TEAMS_DISTRIBUTE_SIMD:
- case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE:
- case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_SIMD:
- case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO:
- case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO:
- case EXEC_OMP_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
- case EXEC_OMP_TARGET_TEAMS_DISTRIBUTE_PARALLEL_DO_SIMD:
- case EXEC_OMP_TARGET_UPDATE:
- case EXEC_OMP_END_CRITICAL:
- case EXEC_OMP_TARGET_ENTER_DATA:
- case EXEC_OMP_TARGET_EXIT_DATA:
- case EXEC_OMP_TARGET_PARALLEL:
- case EXEC_OMP_TARGET_PARALLEL_DO:
- case EXEC_OMP_TARGET_PARALLEL_DO_SIMD:
- case EXEC_OMP_TARGET_SIMD:
- case EXEC_OMP_TASKLOOP:
- case EXEC_OMP_TASKLOOP_SIMD:
- case EXEC_OMP_SCAN:
- case EXEC_OMP_DEPOBJ:
- case EXEC_OMP_PARALLEL_MASTER:
- case EXEC_OMP_PARALLEL_MASTER_TASKLOOP:
- case EXEC_OMP_PARALLEL_MASTER_TASKLOOP_SIMD:
- case EXEC_OMP_MASTER_TASKLOOP:
- case EXEC_OMP_MASTER_TASKLOOP_SIMD:
- case EXEC_OMP_LOOP:
- case EXEC_OMP_PARALLEL_LOOP:
- case EXEC_OMP_TEAMS_LOOP:
- case EXEC_OMP_TARGET_PARALLEL_LOOP:
- case EXEC_OMP_TARGET_TEAMS_LOOP:
- case EXEC_OMP_MASKED:
- case EXEC_OMP_PARALLEL_MASKED:
- case EXEC_OMP_PARALLEL_MASKED_TASKLOOP:
- case EXEC_OMP_PARALLEL_MASKED_TASKLOOP_SIMD:
- case EXEC_OMP_MASKED_TASKLOOP:
- case EXEC_OMP_MASKED_TASKLOOP_SIMD:
- case EXEC_OMP_SCOPE:
- case EXEC_OMP_ERROR:
- case EXEC_OMP_DISPATCH:
- gfc_error ("%s cannot contain OpenMP directive in intervening code "
- "at %L",
- state->name, &code->loc);
- state->errorp = true;
+ case EXEC_OMP_ASSUME:
+ case EXEC_OMP_METADIRECTIVE:
+ /* Per OpenMP 6.0, some non-executable directives are allowed in
+ intervening code. */
break;
case EXEC_CALL:
/* Per OpenMP 5.2, the "omp_" prefix is reserved, so we don't have to
@@ -11518,7 +11609,14 @@ icode_code_error_callback (gfc_code **codep,
}
break;
default:
- break;
+ if (code->op >= EXEC_OMP_FIRST_OPENMP_EXEC
+ && code->op <= EXEC_OMP_LAST_OPENMP_EXEC)
+ {
+ gfc_error ("%s cannot contain OpenMP directive in intervening code "
+ "at %L",
+ state->name, &code->loc);
+ state->errorp = true;
+ }
}
return 0;
}
@@ -12270,7 +12368,8 @@ resolve_omp_do (gfc_code *code)
name, i, &code->loc);
goto fail;
}
- else if (next != do_code->block->next || next->next)
+ else if (next != do_code->block->next
+ || (next->next && next->next->op != EXEC_CONTINUE))
/* Imperfectly nested loop found. */
{
/* Only diagnose violation of imperfect nesting constraints once. */
@@ -12321,16 +12420,166 @@ resolve_omp_do (gfc_code *code)
non_generated_count);
}
+/* Resolve the context selector. In particular, SKIP_P is set to true,
+ the context can never be matched. */
+
+static void
+gfc_resolve_omp_context_selector (gfc_omp_set_selector *oss,
+ bool is_metadirective, bool *skip_p)
+{
+ if (skip_p)
+ *skip_p = false;
+ for (gfc_omp_set_selector *set_selector = oss; set_selector;
+ set_selector = set_selector->next)
+ for (gfc_omp_selector *os = set_selector->trait_selectors; os; os = os->next)
+ {
+ if (os->score)
+ {
+ if (!gfc_resolve_expr (os->score)
+ || os->score->ts.type != BT_INTEGER
+ || os->score->rank != 0)
+ {
+ gfc_error ("%<score%> argument must be constant integer "
+ "expression at %L", &os->score->where);
+ gfc_free_expr (os->score);
+ os->score = nullptr;
+ }
+ else if (os->score->expr_type == EXPR_CONSTANT
+ && mpz_sgn (os->score->value.integer) < 0)
+ {
+ gfc_error ("%<score%> argument must be non-negative at %L",
+ &os->score->where);
+ gfc_free_expr (os->score);
+ os->score = nullptr;
+ }
+ }
+
+ if (os->code == OMP_TRAIT_INVALID)
+ break;
+ enum omp_tp_type property_kind = omp_ts_map[os->code].tp_type;
+ gfc_omp_trait_property *otp = os->properties;
+
+ if (!otp)
+ continue;
+ switch (property_kind)
+ {
+ case OMP_TRAIT_PROPERTY_DEV_NUM_EXPR:
+ case OMP_TRAIT_PROPERTY_BOOL_EXPR:
+ if (!gfc_resolve_expr (otp->expr)
+ || (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR
+ && otp->expr->ts.type != BT_LOGICAL)
+ || (property_kind == OMP_TRAIT_PROPERTY_DEV_NUM_EXPR
+ && otp->expr->ts.type != BT_INTEGER)
+ || otp->expr->rank != 0
+ || (!is_metadirective && otp->expr->expr_type != EXPR_CONSTANT))
+ {
+ if (is_metadirective)
+ {
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
+ gfc_error ("property must be a "
+ "logical expression at %L",
+ &otp->expr->where);
+ else
+ gfc_error ("property must be an "
+ "integer expression at %L",
+ &otp->expr->where);
+ }
+ else
+ {
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
+ gfc_error ("property must be a constant "
+ "logical expression at %L",
+ &otp->expr->where);
+ else
+ gfc_error ("property must be a constant "
+ "integer expression at %L",
+ &otp->expr->where);
+ }
+ /* Prevent later ICEs. */
+ gfc_expr *e;
+ if (property_kind == OMP_TRAIT_PROPERTY_BOOL_EXPR)
+ e = gfc_get_logical_expr (gfc_default_logical_kind,
+ &otp->expr->where, true);
+ else
+ e = gfc_get_int_expr (gfc_default_integer_kind,
+ &otp->expr->where, 0);
+ gfc_free_expr (otp->expr);
+ otp->expr = e;
+ continue;
+ }
+ /* Device number must be conforming, which includes
+ omp_initial_device (-1), omp_invalid_device (-4),
+ and omp_default_device (-5). */
+ if (property_kind == OMP_TRAIT_PROPERTY_DEV_NUM_EXPR
+ && otp->expr->expr_type == EXPR_CONSTANT
+ && mpz_sgn (otp->expr->value.integer) < 0
+ && mpz_cmp_si (otp->expr->value.integer, -1) != 0
+ && mpz_cmp_si (otp->expr->value.integer, -4) != 0
+ && mpz_cmp_si (otp->expr->value.integer, -5) != 0)
+ gfc_error ("property must be a conforming device number at %L",
+ &otp->expr->where);
+ break;
+ default:
+ break;
+ }
+ /* This only handles one specific case: User condition.
+ FIXME: Handle more cases by calling omp_context_selector_matches;
+ unfortunately, we cannot generate the tree here as, e.g., PARM_DECL
+ backend decl are not available at this stage - but might be used in,
+ e.g. user conditions. See PR122361. */
+ if (skip_p && otp
+ && os->code == OMP_TRAIT_USER_CONDITION
+ && otp->expr->expr_type == EXPR_CONSTANT
+ && otp->expr->value.logical == false)
+ *skip_p = true;
+ }
+}
+
+
static void
resolve_omp_metadirective (gfc_code *code, gfc_namespace *ns)
{
gfc_omp_variant *variant = code->ext.omp_variants;
+ gfc_omp_variant *prev_variant = variant;
while (variant)
{
+ bool skip;
+ gfc_resolve_omp_context_selector (variant->selectors, true, &skip);
gfc_code *variant_code = variant->code;
gfc_resolve_code (variant_code, ns);
- variant = variant->next;
+ if (skip)
+ {
+ /* The following should only be true if an error occurred
+ as the 'otherwise' clause should always match. */
+ if (variant == code->ext.omp_variants && !variant->next)
+ break;
+ gfc_omp_variant *tmp = variant;
+ if (variant == code->ext.omp_variants)
+ variant = prev_variant = code->ext.omp_variants = variant->next;
+ else
+ variant = prev_variant->next = variant->next;
+ gfc_free_omp_set_selector_list (tmp->selectors);
+ free (tmp);
+ }
+ else
+ {
+ prev_variant = variant;
+ variant = variant->next;
+ }
+ }
+ /* Replace metadirective by its body if only 'nothing' remains. */
+ if (!code->ext.omp_variants->next && code->ext.omp_variants->stmt == ST_NONE)
+ {
+ gfc_code *next = code->next;
+ gfc_code *inner = code->ext.omp_variants->code;
+ gfc_free_omp_set_selector_list (code->ext.omp_variants->selectors);
+ free (code->ext.omp_variants);
+ *code = *inner;
+ free (inner);
+ while (code->next)
+ code = code->next;
+ code->next = next;
}
}
@@ -12767,9 +13016,21 @@ gfc_resolve_oacc_declare (gfc_namespace *ns)
&& (n->sym->attr.flavor != FL_PROCEDURE
|| n->sym->result != n->sym))
{
- gfc_error ("Object %qs is not a variable at %L",
- n->sym->name, &oc->loc);
- continue;
+ if (n->sym->attr.flavor != FL_PARAMETER)
+ {
+ gfc_error ("Object %qs is not a variable at %L",
+ n->sym->name, &oc->loc);
+ continue;
+ }
+ /* Note that OpenACC 3.4 permits name constants, but the
+ implementation is permitted to ignore the clause;
+ as semantically, device_resident kind of makes sense
+ (and the wording with it is a bit odd), the warning
+ is suppressed. */
+ if (list != OMP_LIST_DEVICE_RESIDENT)
+ gfc_warning (OPT_Wsurprising, "Object %qs at %L is ignored as"
+ " parameters need not be copied", n->sym->name,
+ &oc->loc);
}
if (n->expr && n->expr->ref->type == REF_ARRAY)
@@ -13095,6 +13356,9 @@ gfc_resolve_omp_declare (gfc_namespace *ns)
gfc_omp_declare_variant *odv;
gfc_omp_namelist *range_begin = NULL;
+
+ for (odv = ns->omp_declare_variant; odv; odv = odv->next)
+ gfc_resolve_omp_context_selector (odv->set_selectors, false, nullptr);
for (odv = ns->omp_declare_variant; odv; odv = odv->next)
for (gfc_omp_namelist *n = odv->adjust_args_list; n != NULL; n = n->next)
{