aboutsummaryrefslogtreecommitdiff
path: root/gcc/fortran
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/fortran')
-rw-r--r--gcc/fortran/gfortran.h10
-rw-r--r--gcc/fortran/openmp.cc247
-rw-r--r--gcc/fortran/trans-decl.cc23
-rw-r--r--gcc/fortran/trans-openmp.cc214
4 files changed, 409 insertions, 85 deletions
diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h
index 5fe1276..557c5c7 100644
--- a/gcc/fortran/gfortran.h
+++ b/gcc/fortran/gfortran.h
@@ -1412,7 +1412,15 @@ typedef struct gfc_omp_namelist
bool target;
bool targetsync;
} init;
- bool need_device_ptr;
+ struct
+ {
+ bool need_ptr:1;
+ bool need_addr:1;
+ bool range_start:1;
+ bool omp_num_args_plus:1;
+ bool omp_num_args_minus:1;
+ bool error_p:1;
+ } adj_args;
} u;
union
{
diff --git a/gcc/fortran/openmp.cc b/gcc/fortran/openmp.cc
index e8df9d6..c30ab99 100644
--- a/gcc/fortran/openmp.cc
+++ b/gcc/fortran/openmp.cc
@@ -6718,21 +6718,21 @@ gfc_match_omp_declare_variant (void)
enum clause
{
- match,
- adjust_args,
- append_args
+ clause_match,
+ clause_adjust_args,
+ clause_append_args
} ccode;
if (gfc_match ("match") == MATCH_YES)
- ccode = match;
+ ccode = clause_match;
else if (gfc_match ("adjust_args") == MATCH_YES)
{
- ccode = adjust_args;
+ ccode = clause_adjust_args;
adjust_args_loc = gfc_current_locus;
}
else if (gfc_match ("append_args") == MATCH_YES)
{
- ccode = append_args;
+ ccode = clause_append_args;
append_args_loc = gfc_current_locus;
}
else
@@ -6741,13 +6741,13 @@ gfc_match_omp_declare_variant (void)
break;
}
- if (gfc_match (" (") != MATCH_YES)
+ if (gfc_match (" ( ") != MATCH_YES)
{
gfc_error ("expected %<(%> at %C");
return MATCH_ERROR;
}
- if (ccode == match)
+ if (ccode == clause_match)
{
if (has_match)
{
@@ -6766,32 +6766,160 @@ gfc_match_omp_declare_variant (void)
return MATCH_ERROR;
}
}
- else if (ccode == adjust_args)
+ else if (ccode == clause_adjust_args)
{
has_adjust_args = true;
- bool need_device_ptr_p;
- if (gfc_match (" nothing") == MATCH_YES)
- need_device_ptr_p = false;
- else if (gfc_match (" need_device_ptr") == MATCH_YES)
+ bool need_device_ptr_p = false;
+ bool need_device_addr_p = false;
+ if (gfc_match ("nothing ") == MATCH_YES)
+ ;
+ else if (gfc_match ("need_device_ptr ") == MATCH_YES)
need_device_ptr_p = true;
+ else if (gfc_match ("need_device_addr ") == MATCH_YES)
+ need_device_addr_p = true;
else
{
- gfc_error ("expected %<nothing%> or %<need_device_ptr%> at %C");
+ gfc_error ("expected %<nothing%>, %<need_device_ptr%> or "
+ "%<need_device_addr%> at %C");
return MATCH_ERROR;
}
- gfc_omp_namelist **head = NULL;
- if (gfc_match_omp_variable_list (" :", &odv->adjust_args_list, false,
- NULL, &head)
- != MATCH_YES)
+ if (gfc_match (": ") != MATCH_YES)
{
- gfc_error ("expected argument list at %C");
+ gfc_error ("expected %<:%> at %C");
return MATCH_ERROR;
}
- if (need_device_ptr_p)
- for (gfc_omp_namelist *n = *head; n != NULL; n = n->next)
- n->u.need_device_ptr = true;
+ gfc_omp_namelist *tail = NULL;
+ bool need_range = false, have_range = false;
+ while (true)
+ {
+ gfc_omp_namelist *p = gfc_get_omp_namelist ();
+ p->where = gfc_current_locus;
+ p->u.adj_args.need_ptr = need_device_ptr_p;
+ p->u.adj_args.need_addr = need_device_addr_p;
+ if (tail)
+ {
+ tail->next = p;
+ tail = tail->next;
+ }
+ else
+ {
+ gfc_omp_namelist **q = &odv->adjust_args_list;
+ if (*q)
+ {
+ for (; (*q)->next; q = &(*q)->next)
+ ;
+ (*q)->next = p;
+ }
+ else
+ *q = p;
+ tail = p;
+ }
+ if (gfc_match (": ") == MATCH_YES)
+ {
+ if (have_range)
+ {
+ gfc_error ("unexpected %<:%> at %C");
+ return MATCH_ERROR;
+ }
+ p->u.adj_args.range_start = have_range = true;
+ need_range = false;
+ continue;
+ }
+ if (have_range && gfc_match (", ") == MATCH_YES)
+ {
+ have_range = false;
+ continue;
+ }
+ if (have_range && gfc_match (") ") == MATCH_YES)
+ break;
+ locus saved_loc = gfc_current_locus;
+
+ /* Without ranges, only arg names or integer literals permitted;
+ handle literals here as gfc_match_expr simplifies the expr. */
+ if (gfc_match_literal_constant (&p->expr, true) == MATCH_YES)
+ {
+ gfc_gobble_whitespace ();
+ char c = gfc_peek_ascii_char ();
+ if (c != ')' && c != ',' && c != ':')
+ {
+ gfc_free_expr (p->expr);
+ p->expr = NULL;
+ gfc_current_locus = saved_loc;
+ }
+ }
+ if (!p->expr && gfc_match ("omp_num_args") == MATCH_YES)
+ {
+ if (!have_range)
+ p->u.adj_args.range_start = need_range = true;
+ else
+ need_range = false;
+
+ locus saved_loc2 = gfc_current_locus;
+ gfc_gobble_whitespace ();
+ char c = gfc_peek_ascii_char ();
+ if (c == '+' || c == '-')
+ {
+ if (gfc_match ("+ %e", &p->expr) == MATCH_YES)
+ p->u.adj_args.omp_num_args_plus = true;
+ else if (gfc_match ("- %e", &p->expr) == MATCH_YES)
+ p->u.adj_args.omp_num_args_minus = true;
+ else if (!gfc_error_check ())
+ {
+ gfc_error ("expected constant integer expression "
+ "at %C");
+ p->u.adj_args.error_p = true;
+ return MATCH_ERROR;
+ }
+ p->where = gfc_get_location_range (&saved_loc, 1,
+ &saved_loc, 1,
+ &gfc_current_locus);
+ }
+ else
+ {
+ p->where = gfc_get_location_range (&saved_loc, 1,
+ &saved_loc, 1,
+ &saved_loc2);
+ p->u.adj_args.omp_num_args_plus = true;
+ }
+ }
+ else if (!p->expr)
+ {
+ match m = gfc_match_expr (&p->expr);
+ if (m != MATCH_YES)
+ {
+ gfc_error ("expected dummy parameter name, "
+ "%<omp_num_args%> or constant positive integer"
+ " at %C");
+ p->u.adj_args.error_p = true;
+ return MATCH_ERROR;
+ }
+ if (p->expr->expr_type == EXPR_CONSTANT && !have_range)
+ need_range = true; /* Constant expr but not literal. */
+ p->where = p->expr->where;
+ }
+ else
+ p->where = p->expr->where;
+ gfc_gobble_whitespace ();
+ match m = gfc_match (": ");
+ if (need_range && m != MATCH_YES)
+ {
+ gfc_error ("expected %<:%> at %C");
+ return MATCH_ERROR;
+ }
+ if (m == MATCH_YES)
+ {
+ p->u.adj_args.range_start = have_range = true;
+ need_range = false;
+ continue;
+ }
+ need_range = have_range = false;
+ if (gfc_match (", ") == MATCH_YES)
+ continue;
+ if (gfc_match (") ") == MATCH_YES)
+ break;
+ }
}
- else if (ccode == append_args)
+ else if (ccode == clause_append_args)
{
if (has_append_args)
{
@@ -12817,18 +12945,6 @@ resolve_omp_dispatch (gfc_code *code)
gfc_error ("%<OMP DISPATCH%> directive at %L cannot be followed by a "
"procedure pointer",
&code->loc);
-
- gfc_omp_declare_variant *odv = gfc_current_ns->omp_declare_variant;
- if (odv != NULL)
- for (gfc_omp_namelist *n = odv->adjust_args_list; n != NULL; n = n->next)
- if (n->sym->ts.type != BT_DERIVED || !n->sym->ts.u.derived->ts.is_iso_c
- || (n->sym->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR))
- {
- gfc_error (
- "argument list item %qs in %<need_device_ptr%> at %L must be of "
- "TYPE(C_PTR)",
- n->sym->name, &n->where);
- }
}
/* Resolve OpenMP directive clauses and check various requirements
@@ -12977,18 +13093,59 @@ 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)
for (gfc_omp_namelist *n = odv->adjust_args_list; n != NULL; n = n->next)
- if (n->u.need_device_ptr
- && (!gfc_resolve_expr (n->expr) || n->sym->ts.type != BT_DERIVED
- || !n->sym->ts.u.derived->ts.is_iso_c
- || (n->sym->ts.u.derived->intmod_sym_id != ISOCBINDING_PTR)))
- {
- gfc_error (
- "argument list item %qs in %<need_device_ptr%> at %L must be of "
- "TYPE(C_PTR)",
- n->sym->name, &n->where);
- }
+ {
+ if ((n->expr == NULL
+ && (range_begin
+ || n->u.adj_args.range_start
+ || n->u.adj_args.omp_num_args_plus
+ || n->u.adj_args.omp_num_args_minus))
+ || n->u.adj_args.error_p)
+ {
+ }
+ else if (range_begin
+ || n->u.adj_args.range_start
+ || n->u.adj_args.omp_num_args_plus
+ || n->u.adj_args.omp_num_args_minus)
+ {
+ if (!n->expr
+ || !gfc_resolve_expr (n->expr)
+ || n->expr->expr_type != EXPR_CONSTANT
+ || n->expr->ts.type != BT_INTEGER
+ || n->expr->rank != 0
+ || mpz_sgn (n->expr->value.integer) < 0
+ || ((n->u.adj_args.omp_num_args_plus
+ || n->u.adj_args.omp_num_args_minus)
+ && mpz_sgn (n->expr->value.integer) == 0))
+ {
+ if (n->u.adj_args.omp_num_args_plus
+ || n->u.adj_args.omp_num_args_minus)
+ gfc_error ("Expected constant non-negative scalar integer "
+ "offset expression at %L", &n->where);
+ else
+ gfc_error ("For range-based %<adjust_args%>, a constant "
+ "positive scalar integer expression is required "
+ "at %L", &n->where);
+ }
+ }
+ else if (n->expr
+ && n->expr->expr_type == EXPR_CONSTANT
+ && n->expr->ts.type == BT_INTEGER
+ && mpz_sgn (n->expr->value.integer) > 0)
+ {
+ }
+ else if (!n->expr
+ || !gfc_resolve_expr (n->expr)
+ || n->expr->expr_type != EXPR_VARIABLE)
+ gfc_error ("Expected dummy parameter name or a positive integer "
+ "at %L", &n->where);
+ else if (n->expr->expr_type == EXPR_VARIABLE)
+ n->sym = n->expr->symtree->n.sym;
+
+ range_begin = n->u.adj_args.range_start ? n : NULL;
+ }
}
struct omp_udr_callback_data
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 0acf0e9..ebb63a4 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -6131,6 +6131,19 @@ create_module_nml_decl (gfc_symbol *sym)
}
}
+static void
+gfc_handle_omp_declare_variant (gfc_symbol * sym)
+{
+ if (sym->attr.external
+ && sym->formal_ns
+ && sym->formal_ns->omp_declare_variant)
+ {
+ gfc_namespace *ns = gfc_current_ns;
+ gfc_current_ns = sym->ns;
+ gfc_get_symbol_decl (sym);
+ gfc_current_ns = ns;
+ }
+}
/* Generate all the required code for module variables. */
@@ -6155,6 +6168,11 @@ gfc_generate_module_vars (gfc_namespace * ns)
if (flag_coarray == GFC_FCOARRAY_LIB && has_coarray_vars_or_accessors)
generate_coarray_init (ns);
+ /* For OpenMP, ensure that declare variant in INTERFACE is is processed
+ especially as some late diagnostic is only done on tree level. */
+ if (flag_openmp)
+ gfc_traverse_ns (ns, gfc_handle_omp_declare_variant);
+
cur_module = NULL;
gfc_trans_use_stmts (ns);
@@ -8005,6 +8023,11 @@ gfc_generate_function_code (gfc_namespace * ns)
gfc_conv_cfi_to_gfc (&init, &cleanup, tmp, desc, fsym);
}
+ /* For OpenMP, ensure that declare variant in INTERFACE is is processed
+ especially as some late diagnostic is only done on tree level. */
+ if (flag_openmp)
+ gfc_traverse_ns (ns, gfc_handle_omp_declare_variant);
+
gfc_generate_contained_functions (ns);
has_coarray_vars_or_accessors = caf_accessor_head != NULL;
diff --git a/gcc/fortran/trans-openmp.cc b/gcc/fortran/trans-openmp.cc
index 580d583..233cc0f 100644
--- a/gcc/fortran/trans-openmp.cc
+++ b/gcc/fortran/trans-openmp.cc
@@ -8913,6 +8913,7 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
NULL_TREE, false))
{
tree need_device_ptr_list = NULL_TREE;
+ tree need_device_addr_list = NULL_TREE;
tree append_args_tree = NULL_TREE;
tree id = get_identifier ("omp declare variant base");
tree variant = gfc_get_symbol_decl (variant_proc_sym);
@@ -8926,13 +8927,14 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
if (ns->proc_name->ts.type == BT_CHARACTER)
arg_idx_offset++;
}
+ int nargs = 0;
+ for (gfc_formal_arglist *arg
+ = gfc_sym_get_dummy_args (ns->proc_name);
+ arg; arg = arg->next)
+ nargs++;
if (odv->append_args_list)
{
- int append_arg_no = arg_idx_offset;
- gfc_formal_arglist *arg;
- for (arg = gfc_sym_get_dummy_args (ns->proc_name); arg;
- arg = arg->next)
- append_arg_no++;
+ int append_arg_no = arg_idx_offset + nargs;
tree last_arg = NULL_TREE;
for (gfc_omp_namelist *n = odv->append_args_list;
n != NULL; n = n->next)
@@ -8965,59 +8967,193 @@ gfc_trans_omp_declare_variant (gfc_namespace *ns)
else
append_args_tree = last_arg = t;
}
- /* Store as (purpose = arg number to be used for inserting
- and value = list of interop items. */
+ /* Store as 'purpose' = arg number to be used for inserting
+ and 'value' = list of interop items. */
append_args_tree = build_tree_list (
build_int_cst (integer_type_node,
append_arg_no),
append_args_tree);
}
-
- if (odv->adjust_args_list)
- need_device_ptr_list = make_node (TREE_LIST);
vec<gfc_symbol *> adjust_args_list = vNULL;
for (gfc_omp_namelist *arg_list = odv->adjust_args_list;
arg_list != NULL; arg_list = arg_list->next)
{
- if (!arg_list->sym->attr.dummy)
+ int from, to;
+ if (arg_list->expr == NULL || arg_list->sym)
+ from = ((arg_list->u.adj_args.omp_num_args_minus
+ || arg_list->u.adj_args.omp_num_args_plus)
+ ? nargs : 1);
+ else
{
- gfc_error (
- "list item %qs at %L is not a dummy argument",
- arg_list->sym->name, &arg_list->where);
- continue;
+ if (arg_list->u.adj_args.omp_num_args_plus)
+ mpz_add_ui (arg_list->expr->value.integer,
+ arg_list->expr->value.integer, nargs);
+ if (arg_list->u.adj_args.omp_num_args_minus)
+ mpz_ui_sub (arg_list->expr->value.integer, nargs,
+ arg_list->expr->value.integer);
+ if (mpz_sgn (arg_list->expr->value.integer) <= 0)
+ {
+ gfc_warning (OPT_Wopenmp,
+ "Expected positive argument index "
+ "at %L", &arg_list->where);
+ from = 1;
+ }
+ else
+ from
+ = (mpz_fits_sint_p (arg_list->expr->value.integer)
+ ? mpz_get_si (arg_list->expr->value.integer)
+ : INT_MAX);
+ if (from > nargs)
+ gfc_warning (OPT_Wopenmp,
+ "Argument index at %L exceeds number "
+ "of arguments %d", &arg_list->where,
+ nargs);
}
- if (adjust_args_list.contains (arg_list->sym))
+ locus loc = arg_list->where;
+ if (!arg_list->u.adj_args.range_start)
+ to = from;
+ else
{
- gfc_error ("%qs at %L is specified more than once",
- arg_list->sym->name, &arg_list->where);
- continue;
+ loc = gfc_get_location_range (&arg_list->where, 0,
+ &arg_list->where, 0,
+ &arg_list->next->where);
+ if (arg_list->next->expr == NULL)
+ to = nargs;
+ else
+ {
+ if (arg_list->next->u.adj_args.omp_num_args_plus)
+ mpz_add_ui (arg_list->next->expr->value.integer,
+ arg_list->next->expr->value.integer,
+ nargs);
+ if (arg_list->next->u.adj_args.omp_num_args_minus)
+ mpz_ui_sub (arg_list->next->expr->value.integer,
+ nargs,
+ arg_list->next->expr->value.integer);
+ if (mpz_sgn (arg_list->next->expr->value.integer)
+ <= 0)
+ {
+ gfc_warning (OPT_Wopenmp,
+ "Expected positive argument "
+ "index at %L", &loc);
+ to = 0;
+ }
+ else
+ to = mpz_get_si (
+ arg_list->next->expr->value.integer);
+ }
+ if (from > to && to != 0)
+ gfc_warning (OPT_Wopenmp,
+ "Upper argument index smaller than "
+ "lower one at %L", &loc);
+ if (to > nargs)
+ to = nargs;
+ arg_list = arg_list->next;
}
- adjust_args_list.safe_push (arg_list->sym);
- if (arg_list->u.need_device_ptr)
+ if (from > nargs)
+ continue;
+ /* Change to zero based index. */
+ from--; to--;
+ gfc_formal_arglist *arg = ns->proc_name->formal;
+ if (!arg_list->sym && to >= from)
+ for (int idx = 0; idx < from; idx++)
+ arg = arg->next;
+ for (int idx = from; idx <= to; idx++)
{
- int idx;
- gfc_formal_arglist *arg;
- for (arg = ns->proc_name->formal, idx = 0;
- arg != NULL; arg = arg->next, idx++)
- if (arg->sym == arg_list->sym)
- break;
- gcc_assert (arg != NULL);
- // Store 0-based argument index,
- // as in gimplify_call_expr
- need_device_ptr_list = chainon (
- need_device_ptr_list,
- build_tree_list (
- NULL_TREE,
- build_int_cst (
- integer_type_node,
- idx + arg_idx_offset)));
+ if (idx > from)
+ arg = arg->next;
+ if (arg_list->sym)
+ {
+ for (arg = ns->proc_name->formal, idx = 0;
+ arg != NULL; arg = arg->next, idx++)
+ if (arg->sym == arg_list->sym)
+ break;
+ if (!arg || !arg_list->sym->attr.dummy)
+ {
+ gfc_error ("List item %qs at %L, declared at "
+ "%L, is not a dummy argument",
+ arg_list->sym->name, &loc,
+ &arg_list->sym->declared_at);
+ continue;
+ }
+ }
+ if (arg_list->u.adj_args.need_ptr
+ && (arg->sym->ts.f90_type != BT_VOID
+ || !arg->sym->ts.u.derived->ts.is_iso_c
+ || (arg->sym->ts.u.derived->intmod_sym_id
+ != ISOCBINDING_PTR)
+ || arg->sym->attr.dimension))
+ {
+ gfc_error ("Argument %qs at %L to list item in "
+ "%<need_device_ptr%> at %L must be a "
+ "scalar of TYPE(C_PTR)",
+ arg->sym->name,
+ &arg->sym->declared_at, &loc);
+ if (!arg->sym->attr.value)
+ inform (gfc_get_location (&loc),
+ "Consider using %<need_device_addr%> "
+ "instead");
+ continue;
+ }
+ if (arg_list->u.adj_args.need_addr
+ && arg->sym->attr.value)
+ {
+ gfc_error ("Argument %qs at %L to list item in "
+ "%<need_device_addr%> at %L must not "
+ "have the VALUE attribute",
+ arg->sym->name,
+ &arg->sym->declared_at, &loc);
+ continue;
+ }
+ if (adjust_args_list.contains (arg->sym))
+ {
+ gfc_error ("%qs at %L is specified more than "
+ "once", arg->sym->name, &loc);
+ continue;
+ }
+ adjust_args_list.safe_push (arg->sym);
+
+ if (arg_list->u.adj_args.need_addr)
+ {
+ /* TODO: Has to to support OPTIONAL and array
+ descriptors; should check for CLASS, coarrays?
+ Reject "abc" and 123 as actual arguments (in
+ gimplify.cc or in the FE? Reject noncontiguous
+ actuals? Cf. also PR C++/118859.
+ Also check array-valued type(c_ptr). */
+ static bool warned = false;
+ if (!warned)
+ sorry_at (gfc_get_location (&loc),
+ "%<need_device_addr%> not yet "
+ "supported");
+ warned = true;
+ continue;
+ }
+ if (arg_list->u.adj_args.need_ptr
+ || arg_list->u.adj_args.need_addr)
+ {
+ // Store 0-based argument index,
+ // as in gimplify_call_expr
+ tree t
+ = build_tree_list (
+ NULL_TREE,
+ build_int_cst (integer_type_node,
+ idx + arg_idx_offset));
+ if (arg_list->u.adj_args.need_ptr)
+ need_device_ptr_list
+ = chainon (need_device_ptr_list, t);
+ else
+ need_device_addr_list
+ = chainon (need_device_addr_list, t);
+ }
}
}
tree t = NULL_TREE;
- if (need_device_ptr_list || append_args_tree)
+ if (need_device_ptr_list
+ || need_device_addr_list
+ || append_args_tree)
{
t = build_tree_list (need_device_ptr_list,
- NULL_TREE /*need_device_addr */),
+ need_device_addr_list),
TREE_CHAIN (t) = append_args_tree;
DECL_ATTRIBUTES (variant) = tree_cons (
get_identifier ("omp declare variant variant args"), t,