Hi all, on the fixes side: If a function only appeared in an INTERFACE block, the declare variant handling wasn't triggered - i.e. all diagnostic handled there wasn't.
Additionally, when it was written as such in a module - and the module got used, it wasn't active such that the wrong (the non variant function) was called. This patch handles the INTERFACE block issue of PR115271. The problem that declare variant is not saved in the .mod file still remains. Additionally, when looking at the code, I found a superfluous and wrong check for 'dispatch' - rejecting potentially valid code (example of such included). And it add some feature support by implementing OpenMP 6.0's adjust_args changes - namely, taking an integer (literal?) instead of the dummy argument name - or a numeric range with const expressions and/or 'omp_num_args'. And 'need_device_addr' - however, it currently stops before actually handling the latter by printing a sorry, not yet implemented. [It needs some larger tweaks to handle optional + array descriptors properly. For the C/C++ side, see also PR c++/118859.] Finally, 'type(C_ptr) :: array(:)' is now rejected with need_device_ptr as that's not a simple pointer but uses an array descriptor. That is supposed to work with need_device_addr, though. On the OpenMP side, that was fixed after 6.0 via OpenMP spec Issue #4443. Comments, remarks, suggestions before I commit it? (Build & regtested on x86-64_gnu-linux without offloading. Tobias PS: Follow-up work to be done in that area: - Writing 'omp declare variant' to .mod files → PR115271 [wrong-code issue] - Handling need_device_addr + fixing wrong-code part of PR c++/118859 (relate; fixing the diagnostic should also be done) [wrong-code + feature issue; for C++ also diagnostic/accepts-invalid] - Adding some more valid testcases (as part of ↑?) [also useful]
OpenMP/Fortran: extend 'adjust_args' clause, fixes for it and declare variant [PR115271] On the extension side, it implements OpenMP 6.0's numeric values/ranges for the adjust_args arguments, including 'omp_num_args'. And it adds parser support for need_device_addr. It also implements the post-OpenMP-6.0 clarification of OpenMP spec Issue #4443 regarding type(c_ptr) with dimension being invalid for need_device_ptr. To be done: Adding full support for need_device_addr (optional, array descriptor, ...). On the invalid side, it removed a bogus c_ptr check that went through all adjust_args without checking for need_device_ptr and the current scope. And it finally also processes 'declare variant' in an INTERFACE block, which is part of PR115271, but it does not handle .mod file yet - the main issue tracked in that PR. PR fortran/115271 gcc/fortran/ChangeLog: * gfortran.h (gfc_omp_namelist): Change need_device_ptr to adj_args union and add more flags. * openmp.cc (gfc_match_omp_declare_variant, gfc_resolve_omp_declare): For adjust_args, handle need_device_addr and numeric values/ranges besides dummy argument names. (resolve_omp_dispatch): Remove bogus a adjust_args check. * trans-decl.cc (gfc_handle_declare_variant): New. (gfc_generate_module_vars, gfc_generate_function_code): Call it. * trans-openmp.cc (gfc_trans_omp_declare_variant): Handle numeric values/ranges besides dummy argument names. gcc/testsuite/ChangeLog: * gfortran.dg/gomp/adjust-args-1.f90: Update dg-.* expectations. * gfortran.dg/gomp/adjust-args-2.f90: Likewise. * gfortran.dg/gomp/adjust-args-2a.f90: Likewise. * gfortran.dg/gomp/adjust-args-3.f90: Likewise. * gfortran.dg/gomp/adjust-args-4.f90: Remove array from c_ptr. * gfortran.dg/gomp/adjust-args-5.f90: Likewise. * gfortran.dg/gomp/adjust-args-11.f90: Likewise. Add check that INTERFACE is now handled in subroutines and in modules. * gfortran.dg/gomp/adjust-args-13.f90: New test. * gfortran.dg/gomp/adjust-args-14.f90: New test. * gfortran.dg/gomp/adjust-args-15.f90: New test. * gfortran.dg/gomp/declare-variant-21.f90: New test. gcc/fortran/gfortran.h | 10 +- gcc/fortran/openmp.cc | 247 +++++++++++++++++---- gcc/fortran/trans-decl.cc | 23 ++ gcc/fortran/trans-openmp.cc | 212 ++++++++++++++---- gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90 | 8 +- gcc/testsuite/gfortran.dg/gomp/adjust-args-11.f90 | 77 ++++++- gcc/testsuite/gfortran.dg/gomp/adjust-args-13.f90 | 18 ++ gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 | 85 +++++++ gcc/testsuite/gfortran.dg/gomp/adjust-args-15.f90 | 35 +++ gcc/testsuite/gfortran.dg/gomp/adjust-args-2.f90 | 3 +- gcc/testsuite/gfortran.dg/gomp/adjust-args-2a.f90 | 8 +- gcc/testsuite/gfortran.dg/gomp/adjust-args-3.f90 | 4 +- gcc/testsuite/gfortran.dg/gomp/adjust-args-4.f90 | 8 +- gcc/testsuite/gfortran.dg/gomp/adjust-args-5.f90 | 8 +- .../gfortran.dg/gomp/declare-variant-21.f90 | 20 ++ 15 files changed, 660 insertions(+), 106 deletions(-) diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 5fe12764615..557c5c76f41 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 e8df9d63fec..c30ab997f76 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 0acf0e9adb7..7c474d288a5 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_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_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_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 580d5837bd5..13f096324bc 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,191 @@ 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 (odv->adjust_args_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, diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90 index c0c06e7f8fd..39824c29701 100644 --- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-1.f90 @@ -21,7 +21,7 @@ module main integer function f3 (a) import c_ptr type(c_ptr), intent(inout) :: a - !$omp declare variant (f1) match (construct={dispatch}) adjust_args (other: a) ! { dg-error "expected 'nothing' or 'need_device_ptr' at .1." } + !$omp declare variant (f1) match (construct={dispatch}) adjust_args (other: a) ! { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' at .1." } end function integer function f4 (a) import c_ptr @@ -30,15 +30,15 @@ module main end function integer function f5 (i) integer, intent(inout) :: i - !$omp declare variant (f1) match (construct={dispatch}) adjust_args () ! { dg-error "expected 'nothing' or 'need_device_ptr' at .1." } + !$omp declare variant (f1) match (construct={dispatch}) adjust_args () ! { dg-error "expected 'nothing', 'need_device_ptr' or 'need_device_addr' at .1." } end function integer function f6 (i) integer, intent(inout) :: i - !$omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing) ! { dg-error "expected argument list at .1." } + !$omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing) ! { dg-error "expected ':' at .1." } end function integer function f7 (i) integer, intent(inout) :: i - !$omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing:) ! { dg-error "expected argument list at .1." } + !$omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing:) ! { dg-error "expected dummy parameter name, 'omp_num_args' or constant positive integer at .1." } end function end interface diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-11.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-11.f90 index d2eb7c1d72c..6586abc661c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-11.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-11.f90 @@ -18,13 +18,13 @@ module main import c_ptr integer, intent(in) :: a type(c_ptr), intent(inout) :: b - type(c_ptr), intent(out) :: c(:) + type(c_ptr), intent(out) :: c end function integer function f0(a, b, c) import c_ptr integer, intent(in) :: a type(c_ptr), intent(inout) :: b - type(c_ptr), intent(out) :: c(:) + type(c_ptr), intent(out) :: c !$omp declare variant (f), match (construct={dispatch}) , & !$omp& adjust_args (nothing: a) ,adjust_args (need_device_ptr: b),adjust_args (need_device_ptr: c) end function @@ -43,3 +43,76 @@ subroutine test end subroutine end module + +module other + use iso_c_binding, only: c_ptr + implicit none + + interface + integer function g(a, b, c) + import c_ptr + integer, intent(in) :: a + type(c_ptr), intent(inout) :: b + type(c_ptr), intent(out) :: c(:) + end function + integer function g0(a, b, c) ! { dg-error "Argument 'c' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } + import c_ptr + integer, intent(in) :: a + type(c_ptr), intent(inout) :: b + type(c_ptr), intent(out) :: c(:) + !$omp declare variant (g), match (construct={dispatch}) , & + !$omp& adjust_args (nothing: a) ,adjust_args (need_device_ptr: b),adjust_args (need_device_ptr: c) ! { dg-error "Argument 'c' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } +! { dg-note "Consider using 'need_device_addr' instead" "" { target *-*-* } .-1 } + end function + end interface +end module + +subroutine foobar + use iso_c_binding, only: c_ptr + implicit none + + interface + integer function h(a, b, c) + import c_ptr + integer, intent(in) :: a + type(c_ptr), intent(inout) :: b + type(c_ptr), intent(out) :: c(:) + end function + integer function h0(a, b, c) ! { dg-error "Argument 'c' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } + import c_ptr + integer, intent(in) :: a + type(c_ptr), intent(inout) :: b + type(c_ptr), intent(out) :: c(:) + !$omp declare variant (h), match (construct={dispatch}) , & + !$omp& adjust_args (nothing: a) ,adjust_args (need_device_ptr: b),adjust_args (need_device_ptr: c) ! { dg-error "Argument 'c' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } +! { dg-note "Consider using 'need_device_addr' instead" "" { target *-*-* } .-1 } + end function + end interface +end + + +subroutine outer +contains +subroutine inner + use iso_c_binding, only: c_ptr + implicit none + + interface + integer function st(a, b, c) + import c_ptr + integer, intent(in) :: a + type(c_ptr), intent(inout) :: b + type(c_ptr), intent(out) :: c(:) + end function + integer function st0(a, b, c) ! { dg-error "Argument 'c' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } + import c_ptr + integer, intent(in) :: a + type(c_ptr), intent(inout) :: b + type(c_ptr), intent(out) :: c(:) + !$omp declare variant (st), match (construct={dispatch}) , & + !$omp& adjust_args (nothing: a) ,adjust_args (need_device_ptr: b),adjust_args (need_device_ptr: c) ! { dg-error "Argument 'c' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } +! { dg-note "Consider using 'need_device_addr' instead" "" { target *-*-* } .-1 } + end function + end interface +end subroutine inner +end subroutine outer diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-13.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-13.f90 new file mode 100644 index 00000000000..319a0076d1c --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-13.f90 @@ -0,0 +1,18 @@ +! This failed with a bogus: +! 'must be of TYPE(C_PTR)' +module m + implicit none +contains + subroutine q() + end + subroutine one(x) + integer :: x + end + subroutine two(x) + !$omp declare variant(one) match(construct={dispatch}) adjust_args(nothing: x) + integer :: x + + !$omp dispatch + call q + end +end diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 new file mode 100644 index 00000000000..e644fd7060e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-14.f90 @@ -0,0 +1,85 @@ +module m + implicit none +contains + subroutine f(x,y,z) + integer:: x, y, z + value :: y + end subroutine + subroutine f0(x,y,z) + !$omp declare variant(f) adjust_args ( need_device_addr : : omp_num_args-1) & + !$omp& adjust_args ( need_device_ptr : z) & + !$omp& match ( construct = { dispatch } ) + integer:: x, y, z + value :: y + +! { dg-error "19: Argument 'y' at .1. to list item in 'need_device_addr' at .2. must not have the VALUE attribute" "" { target *-*-* } 8 } +! { dg-error "62: Argument 'y' at .1. to list item in 'need_device_addr' at .2. must not have the VALUE attribute" "" { target *-*-* } 9 } +! { dg-message "sorry, unimplemented: 'need_device_addr' not yet supported" "" { target *-*-* } 9 } + +! { dg-error "Argument 'z' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" "" { target *-*-* } 8 } +! { dg-error "Argument 'z' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" "" { target *-*-* } 10 } +! { dg-note "Consider using 'need_device_addr' instead" "" { target *-*-* } 10 } + end subroutine +end module m + +module m2 + use iso_c_binding, only: c_ptr + implicit none + interface + subroutine f(x,y,z) + import + type(c_ptr) :: x, y, z + end subroutine + subroutine f0(x,y,z) + import + type(c_ptr) :: x, y, z + !$omp declare variant(f) adjust_args ( need_device_ptr : : ) & + !$omp& adjust_args ( nothing : 2, 4) & + !$omp& match ( construct = { dispatch } ) + +! { dg-error "54: 'y' at .1. is specified more than once" "" { target *-*-* } 37 } +! { dg-warning "57: Argument index at .1. exceeds number of arguments 3 \\\[-Wopenmp\\\]" "" { target *-*-* } 37 } + end subroutine + end interface +end module m2 + +module m3 + use iso_c_binding, only: c_ptr + implicit none + interface + subroutine f(x,y,z) + import + type(c_ptr) :: x, y, z + end subroutine + subroutine f0(x,y,z) + import + type(c_ptr) :: x, y, z + !$omp declare variant(f) adjust_args ( need_device_addr : omp_num_args -4 :, 3 : 2) & + !$omp& match ( construct = { dispatch } ) +! { dg-warning "63: Expected positive argument index at .1. \\\[-Wopenmp\\\]" "" { target *-*-* } .-2 } +! { dg-warning "82: Upper argument index smaller than lower one at .1. \\\[-Wopenmp\\\]" "" { target *-*-* } .-3 } + end subroutine + end interface +end module m3 + +module m4 + use iso_c_binding, only: c_ptr + implicit none + interface + subroutine f(x,y,z) + import + type(c_ptr) :: x, y, z + end subroutine + subroutine f0(x,y,z) + import + type(c_ptr) :: x, y, z + !$omp declare variant(f) adjust_args ( need_device_addr : x, y, omp_num_args -2 : omp_num_args -1) & + !$omp& adjust_args ( need_device_addr : z) & + !$omp& adjust_args ( need_device_addr : omp_num_args : 3) & + !$omp& match ( construct = { dispatch } ) +! { dg-error "69: 'x' at .1. is specified more than once" "" { target *-*-* } .-4 } +! { dg-error "69: 'y' at .1. is specified more than once" "" { target *-*-* } .-5 } +! { dg-error "63: 'z' at .1. is specified more than once" "" { target *-*-* } .-4 } + end subroutine + end interface +end module m4 diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-15.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-15.f90 new file mode 100644 index 00000000000..d1001c18318 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-15.f90 @@ -0,0 +1,35 @@ +module m3 + use iso_c_binding, only: c_ptr + implicit none + interface + subroutine f(x,y,z) + import + type(c_ptr) :: x, y, z + end subroutine + subroutine f0(x,y,z) + import + type(c_ptr) :: x, y, z + !$omp declare variant(f) adjust_args ( need_device_addr : -1 : omp_num_args + 10 ) & ! { dg-error "64: For range-based 'adjust_args', a constant positive scalar integer expression is required" } + !$omp& adjust_args ( nothing : 1+1) & ! { dg-error "expected ':'" } + !$omp& match ( construct = { dispatch } ) + end subroutine + end interface +end module m3 + +module m4 + use iso_c_binding, only: c_ptr + implicit none + interface + subroutine f(x,y,z) + import + type(c_ptr) :: x, y, z + end subroutine + subroutine f0(x,y,z) + import + type(c_ptr) :: x, y, z + !$omp declare variant(f) adjust_args ( need_device_addr : 3.3 ) & ! { dg-error "Expected dummy parameter name or a positive integer" } + !$omp& adjust_args ( nothing : 1 : y ) & ! { dg-error "For range-based 'adjust_args', a constant positive scalar integer expression is required" } + !$omp& match ( construct = { dispatch } ) + end subroutine + end interface +end module m4 diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-2.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-2.f90 index c65a4839ca5..35acf82a7fe 100644 --- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-2.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-2.f90 @@ -12,7 +12,8 @@ contains subroutine f3 (i) integer, intent(inout) :: i - !$omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing: z) ! { dg-error "Symbol 'z' at .1. has no IMPLICIT type" } + !$omp declare variant (f1) match (construct={dispatch}) adjust_args (nothing: z) ! { dg-error "Symbol 'z' at .1. has no IMPLICIT type" } +! { dg-error "Expected dummy parameter name or a positive integer at .1." "" { target *-*-* } .-1 } end subroutine end module diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-2a.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-2a.f90 index 9a32d2b7d92..d4244ce14e6 100644 --- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-2a.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-2a.f90 @@ -15,13 +15,13 @@ module main end interface contains - subroutine f9 (i) + subroutine f9 (i) ! { dg-error "Argument 'i' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } integer, intent(inout) :: i - !$omp declare variant (f1) match (construct={dispatch}) adjust_args (need_device_ptr: i) ! { dg-error "argument list item 'i' in 'need_device_ptr' at .1. must be of TYPE.C_PTR." } + !$omp declare variant (f1) match (construct={dispatch}) adjust_args (need_device_ptr: i) ! { dg-error "Argument 'i' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } end subroutine - subroutine f13 (a) + subroutine f13 (a) ! { dg-error "Argument 'a' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } type(c_funptr), intent(inout) :: a - !$omp declare variant (h) match (construct={dispatch}) adjust_args (need_device_ptr: a) ! { dg-error "argument list item 'a' in 'need_device_ptr' at .1. must be of TYPE.C_PTR." } + !$omp declare variant (h) match (construct={dispatch}) adjust_args (need_device_ptr: a) ! { dg-error "Argument 'a' at .1. to list item in 'need_device_ptr' at .2. must be a scalar of TYPE\\(C_PTR\\)" } end subroutine subroutine test diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-3.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-3.f90 index 9033221cc5c..4ad64c22d6f 100644 --- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-3.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-3.f90 @@ -4,7 +4,7 @@ module main use iso_c_binding, only: c_ptr implicit none - type(c_ptr) :: b + type(c_ptr) :: b ! { dg-error "List item 'b' at .1., declared at .2., is not a dummy argument" } contains subroutine base2 (a) @@ -17,7 +17,7 @@ contains end subroutine subroutine base4 (a) type(c_ptr), intent(inout) :: a - !$omp declare variant (variant2) match (construct={dispatch}) adjust_args (need_device_ptr: b) ! { dg-error "list item 'b' at .1. is not a dummy argument" } + !$omp declare variant (variant2) match (construct={dispatch}) adjust_args (need_device_ptr: b) ! { dg-error "List item 'b' at .1., declared at .2., is not a dummy argument" } end subroutine subroutine variant2 (a) diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-4.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-4.f90 index 2f44c0026db..7452e12ff0c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-4.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-4.f90 @@ -15,13 +15,13 @@ module main import c_ptr integer, intent(in) :: a type(c_ptr), intent(inout) :: b - type(c_ptr), intent(out) :: c(:) + type(c_ptr), intent(out) :: c end function integer function f0(a, b, c) import c_ptr integer, intent(in) :: a type(c_ptr), intent(inout) :: b - type(c_ptr), intent(out) :: c(:) + type(c_ptr), intent(out) :: c !$omp declare variant (f) match (construct={dispatch}) & !$omp& adjust_args (nothing: a) adjust_args (need_device_ptr: b, c) end function @@ -29,7 +29,7 @@ module main import c_ptr integer, intent(in) :: a type(c_ptr), intent(inout) :: b - type(c_ptr), intent(out) :: c(:) + type(c_ptr), intent(out) :: c !$omp declare variant (f) match (construct={dispatch}) & !$omp& adjust_args (nothing: a) adjust_args (need_device_ptr: b) adjust_args (need_device_ptr: c) end function @@ -54,5 +54,5 @@ end subroutine end module ! { dg-final { scan-tree-dump-times "__builtin_omp_get_default_device \\(\\);" 2 "gimple" } } -! { dg-final { scan-tree-dump-times "D\.\[0-9]+ = __builtin_omp_get_mapped_ptr \\(parm\.\[0-9]+, D\.\[0-9]+\\);" 2 "gimple" } } +! { dg-final { scan-tree-dump-times "D\.\[0-9]+ = __builtin_omp_get_mapped_ptr \\(c, D\.\[0-9]+\\);" 2 "gimple" } } ! { dg-final { scan-tree-dump-times "D\.\[0-9]+ = __builtin_omp_get_mapped_ptr \\(b\.\[0-9]+, D\.\[0-9]+\\);" 2 "gimple" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/adjust-args-5.f90 b/gcc/testsuite/gfortran.dg/gomp/adjust-args-5.f90 index 2f44c0026db..7452e12ff0c 100644 --- a/gcc/testsuite/gfortran.dg/gomp/adjust-args-5.f90 +++ b/gcc/testsuite/gfortran.dg/gomp/adjust-args-5.f90 @@ -15,13 +15,13 @@ module main import c_ptr integer, intent(in) :: a type(c_ptr), intent(inout) :: b - type(c_ptr), intent(out) :: c(:) + type(c_ptr), intent(out) :: c end function integer function f0(a, b, c) import c_ptr integer, intent(in) :: a type(c_ptr), intent(inout) :: b - type(c_ptr), intent(out) :: c(:) + type(c_ptr), intent(out) :: c !$omp declare variant (f) match (construct={dispatch}) & !$omp& adjust_args (nothing: a) adjust_args (need_device_ptr: b, c) end function @@ -29,7 +29,7 @@ module main import c_ptr integer, intent(in) :: a type(c_ptr), intent(inout) :: b - type(c_ptr), intent(out) :: c(:) + type(c_ptr), intent(out) :: c !$omp declare variant (f) match (construct={dispatch}) & !$omp& adjust_args (nothing: a) adjust_args (need_device_ptr: b) adjust_args (need_device_ptr: c) end function @@ -54,5 +54,5 @@ end subroutine end module ! { dg-final { scan-tree-dump-times "__builtin_omp_get_default_device \\(\\);" 2 "gimple" } } -! { dg-final { scan-tree-dump-times "D\.\[0-9]+ = __builtin_omp_get_mapped_ptr \\(parm\.\[0-9]+, D\.\[0-9]+\\);" 2 "gimple" } } +! { dg-final { scan-tree-dump-times "D\.\[0-9]+ = __builtin_omp_get_mapped_ptr \\(c, D\.\[0-9]+\\);" 2 "gimple" } } ! { dg-final { scan-tree-dump-times "D\.\[0-9]+ = __builtin_omp_get_mapped_ptr \\(b\.\[0-9]+, D\.\[0-9]+\\);" 2 "gimple" } } diff --git a/gcc/testsuite/gfortran.dg/gomp/declare-variant-21.f90 b/gcc/testsuite/gfortran.dg/gomp/declare-variant-21.f90 new file mode 100644 index 00000000000..da53c1f1fa3 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/gomp/declare-variant-21.f90 @@ -0,0 +1,20 @@ +! { dg-additional-options "-fdump-tree-gimple" } +! { dg-final { scan-tree-dump-not "g \\(\\)" "gimple" } } +! { dg-final { scan-tree-dump "i = f \\(\\);" "gimple" } } + +! PR fortran/115271 + +module m +interface + integer function f () + end + integer function g () + !$omp declare variant(f) match(construct={dispatch}) + end +end interface +end + +use m +!$omp dispatch + i = g() +end