[PATCH v2 0/7] fortran: Ignore unused arguments for scalarisation [PR97896]
Hello, This is the second submit of a patch series whose first version[1] was not welcome because of its C++ usage. After some thought I figured out that rewriting the series without C++ features would not be that impacting after all. So here you go, the (not so) good old-fashioned way. The problematic case is intrinsic procedures where an argument is actually not used in the code generated (KIND argument of INDEX in the testcase), which confuses the scalariser. Thomas König comitted a change to workaround the problem, but it regressed in PR97896. These patch put the workaround where I think it is more appropriate, namely at the beginning of the scalarisation procedure. This is the patch 7 of the series, preceded with the revert in patch 6. I intend to commit both of them squashed together. The rest of the series (patches 1-5) is preliminary work to be able to identify the KIND argument of the INDEX intrinsic by its name, rather than using the right number of next->next->next indirections starting with the first argument. It is probably overkill for just this use case, but I think it’s worth having that facility in the long term. I intend to submit a separate patch for the release branch with only patch 6 and 7 and the next->next->next indirections. Regression-tested on x86_64-linux-gnu. Ok for master? [1] https://gcc.gnu.org/pipermail/fortran/2021-August/056303.html Mikael Morin (7): fortran: new wrapper class gfc_dummy_arg fortran: Tiny sort_actual internal refactoring fortran: Reverse actual vs dummy argument mapping fortran: simplify elemental arguments walking fortran: Delete redundant missing_arg_type field Revert "Remove KIND argument from INDEX so it does not mess up scalarization." fortran: Ignore unused args in scalarization [PR97896] gcc/fortran/gfortran.h| 41 +-- gcc/fortran/interface.c | 77 ++-- gcc/fortran/intrinsic.c | 101 +++--- gcc/fortran/intrinsic.h | 3 +- gcc/fortran/iresolve.c| 21 +- gcc/fortran/trans-array.c | 74 ++- gcc/fortran/trans-array.h | 5 +- gcc/fortran/trans-decl.c | 24 +- gcc/fortran/trans-expr.c | 9 ++- gcc/fortran/trans-intrinsic.c | 3 +- gcc/fortran/trans-stmt.c | 30 gcc/fortran/trans.h | 4 +- gcc/testsuite/gfortran.dg/index_5.f90 | 23 ++ 13 files changed, 262 insertions(+), 153 deletions(-) create mode 100644 gcc/testsuite/gfortran.dg/index_5.f90 -- 2.30.2
[PATCH v2 1/7] fortran: new wrapper class gfc_dummy_arg
Introduce a new wrapper class gfc_dummy_arg that provides a common interface to both dummy arguments of user-defined procedures (which have type gfc_formal_arglist) and dummy arguments of intrinsic procedures (which have type gfc_intrinsic_arg). gcc/fortran/ * gfortran.h (gfc_dummy_arg_kind, gfc_dummy_arg): New. --- gcc/fortran/gfortran.h | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 921aed93dc3..55ac4a80549 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2169,11 +2169,29 @@ typedef struct gfc_intrinsic_arg gfc_actual_arglist *actual; struct gfc_intrinsic_arg *next; - } gfc_intrinsic_arg; +typedef enum { + GFC_UNDEFINED_DUMMY_ARG = 0, + GFC_INTRINSIC_DUMMY_ARG, + GFC_NON_INTRINSIC_DUMMY_ARG +} +gfc_dummy_arg_kind; + +/* dummy arg of either an intrinsic or a user-defined procedure. */ +struct gfc_dummy_arg +{ + gfc_dummy_arg_kind kind; + + union { +gfc_intrinsic_arg *intrinsic; +gfc_formal_arglist *non_intrinsic; + } u; +}; + + /* Specifies the various kinds of check functions used to verify the argument lists of intrinsic functions. fX with X an integer refer to check functions of intrinsics with X arguments. f1m is used for
[PATCH v2 2/7] fortran: Tiny sort_actual internal refactoring
Preliminary refactoring to make further changes more obvious. No functional change. gcc/fortran/ * intrinsic.c (sort_actual): initialise variable and use it earlier. --- gcc/fortran/intrinsic.c | 7 +++ 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index 219f04f2317..ffeaf2841b7 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -4411,19 +4411,18 @@ do_sort: for (f = formal; f; f = f->next) { - if (f->actual && f->actual->label != NULL && f->ts.type) + a = f->actual; + if (a && a->label != NULL && f->ts.type) { gfc_error ("ALTERNATE RETURN not permitted at %L", where); return false; } - if (f->actual == NULL) + if (a == NULL) { a = gfc_get_actual_arglist (); a->missing_arg_type = f->ts.type; } - else - a = f->actual; if (actual == NULL) *ap = a;
[PATCH v2 3/7] fortran: Reverse actual vs dummy argument mapping
There was originally no way from an actual argument to get to the corresponding dummy argument, even if the job of sorting and matching actual with dummy arguments was done. The closest was a field named actual in gfc_intrinsic_arg that was used as scratch data when sorting arguments of one specific call. However that value was overwritten later on as arguments of another call to the same procedure were sorted and matched. This change removes that field and adds instead a new field associated_dummy in gfc_actual_arglist. This field uses the just introduced gfc_dummy_arg interface, which makes it usable with both external and intrinsic procedure dummy arguments. As the removed field was used in the code sorting and matching arguments, that code has to be updated. Two local vectors with matching indices are introduced for respectively dummy and actual arguments, and the loops are modified to use indices and update those argument vectors. gcc/fortran/ * gfortran.h (gfc_actual_arglist): New field associated_dummy. (gfc_intrinsic_arg): Remove field actual. * interface.c (get_nonintrinsic_dummy_arg): New. (gfc_compare_actual): Initialize associated_dummy. * intrinsic.c (get_intrinsic_dummy_arg): New. (sort_actual): Add argument vectors. Use loops with indices on argument vectors. Initialize associated_dummy. --- gcc/fortran/gfortran.h | 11 ++- gcc/fortran/interface.c | 21 ++-- gcc/fortran/intrinsic.c | 43 ++--- 3 files changed, 61 insertions(+), 14 deletions(-) diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 55ac4a80549..c890d80bce0 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1144,6 +1144,9 @@ gfc_formal_arglist; #define gfc_get_formal_arglist() XCNEW (gfc_formal_arglist) +struct gfc_dummy_arg; + + /* The gfc_actual_arglist structure is for actual arguments and for type parameter specification lists. */ typedef struct gfc_actual_arglist @@ -1160,6 +1163,11 @@ typedef struct gfc_actual_arglist gfc_param_spec_type spec_type; struct gfc_expr *expr; + + /* The dummy arg this actual arg is associated with, if the interface + is explicit. NULL otherwise. */ + gfc_dummy_arg *associated_dummy; + struct gfc_actual_arglist *next; } gfc_actual_arglist; @@ -2166,7 +2174,6 @@ typedef struct gfc_intrinsic_arg gfc_typespec ts; unsigned optional:1, value:1; ENUM_BITFIELD (sym_intent) intent:2; - gfc_actual_arglist *actual; struct gfc_intrinsic_arg *next; } @@ -2191,6 +2198,8 @@ struct gfc_dummy_arg } u; }; +#define gfc_get_dummy_arg() XCNEW (gfc_dummy_arg) + /* Specifies the various kinds of check functions used to verify the argument lists of intrinsic functions. fX with X an integer refer diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 9e3e8aa9da9..dba167559d1 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -3026,6 +3026,18 @@ lookup_arg_fuzzy (const char *arg, gfc_formal_arglist *arguments) } +static gfc_dummy_arg * +get_nonintrinsic_dummy_arg (gfc_formal_arglist *formal) +{ + gfc_dummy_arg * const dummy_arg = gfc_get_dummy_arg (); + + dummy_arg->kind = GFC_NON_INTRINSIC_DUMMY_ARG; + dummy_arg->u.non_intrinsic = formal; + + return dummy_arg; +} + + /* Given formal and actual argument lists, see if they are compatible. If they are compatible, the actual argument list is sorted to correspond with the formal list, and elements for missing optional @@ -3131,6 +3143,8 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, "call at %L", where); return false; } + else + a->associated_dummy = get_nonintrinsic_dummy_arg (f); if (a->expr == NULL) { @@ -3546,9 +3560,12 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, /* The argument lists are compatible. We now relink a new actual argument list with null arguments in the right places. The head of the list remains the head. */ - for (i = 0; i < n; i++) + for (f = formal, i = 0; f; f = f->next, i++) if (new_arg[i] == NULL) - new_arg[i] = gfc_get_actual_arglist (); + { + new_arg[i] = gfc_get_actual_arglist (); + new_arg[i]->associated_dummy = get_nonintrinsic_dummy_arg (f); + } if (na != 0) { diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index ffeaf2841b7..c42891e7e1a 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -4269,6 +4269,18 @@ remove_nullargs (gfc_actual_arglist **ap) } +static gfc_dummy_arg * +get_intrinsic_dummy_arg (gfc_intrinsic_arg *intrinsic) +{ + gfc_dummy_arg * const dummy_arg = gfc_get_dummy_arg (); + + dummy_arg->kind = GFC_INTRINSIC_DUMMY_ARG; + dummy_arg->u.intrinsic = intrinsic; + + return dummy_arg; +} + + /* Given an actual arglist and a formal arglist, sort the actual arglis
[PATCH v2 4/7] fortran: simplify elemental arguments walking
This adds two functions working with the wrapper class gfc_dummy_arg and makes usage of them to simplify a bit the walking of elemental procedure arguments for scalarization. As information about dummy arguments can be obtained from the actual argument through the just-introduced associated_dummy field, there is no need to carry around the procedure interface and walk dummy arguments manually together with actual arguments. gcc/fortran/ * interface.c (gfc_dummy_arg_get_typespec, gfc_dummy_arg_is_optional): New functions. * gfortran.h (gfc_dummy_arg_get_typespec, gfc_dummy_arg_is_optional): Declare them. * trans.h (gfc_ss_info::dummy_arg): Use the wrapper type as declaration type. * trans-array.c (gfc_scalar_elemental_arg_saved_as_reference): use gfc_dummy_arg_get_typespec function to get the type. (gfc_walk_elemental_function_args): Remove proc_ifc argument. Get info about the dummy arg using the associated_dummy field. * trans-array.h (gfc_walk_elemental_function_args): Update declaration. * trans-intrinsic.c (gfc_walk_intrinsic_function): Update call to gfc_walk_elemental_function_args. * trans-stmt.c (gfc_trans_call): Ditto. (get_proc_ifc_for_call): Remove. --- gcc/fortran/gfortran.h| 4 gcc/fortran/interface.c | 34 ++ gcc/fortran/trans-array.c | 23 +++ gcc/fortran/trans-array.h | 2 +- gcc/fortran/trans-intrinsic.c | 2 +- gcc/fortran/trans-stmt.c | 22 -- gcc/fortran/trans.h | 4 ++-- 7 files changed, 49 insertions(+), 42 deletions(-) diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index c890d80bce0..12dd33bf74f 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2201,6 +2201,10 @@ struct gfc_dummy_arg #define gfc_get_dummy_arg() XCNEW (gfc_dummy_arg) +const gfc_typespec & gfc_dummy_arg_get_typespec (gfc_dummy_arg &); +bool gfc_dummy_arg_is_optional (gfc_dummy_arg &); + + /* Specifies the various kinds of check functions used to verify the argument lists of intrinsic functions. fX with X an integer refer to check functions of intrinsics with X arguments. f1m is used for diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index dba167559d1..d463ee8228a 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -5403,3 +5403,37 @@ gfc_get_formal_from_actual_arglist (gfc_symbol *sym, f = &((*f)->next); } } + + +const gfc_typespec & +gfc_dummy_arg_get_typespec (gfc_dummy_arg & dummy_arg) +{ + switch (dummy_arg.kind) +{ +case GFC_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.intrinsic->ts; + +case GFC_NON_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.non_intrinsic->sym->ts; + +default: + gcc_unreachable (); +} +} + + +bool +gfc_dummy_arg_is_optional (gfc_dummy_arg & dummy_arg) +{ + switch (dummy_arg.kind) +{ +case GFC_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.intrinsic->optional; + +case GFC_NON_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.non_intrinsic->sym->attr.optional; + +default: + gcc_unreachable (); +} +} diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 0d013defdbb..6ae72a354e5 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -2879,7 +2879,8 @@ gfc_scalar_elemental_arg_saved_as_reference (gfc_ss_info * ss_info) /* If the expression is of polymorphic type, it's actual size is not known, so we avoid copying it anywhere. */ if (ss_info->data.scalar.dummy_arg - && ss_info->data.scalar.dummy_arg->ts.type == BT_CLASS + && gfc_dummy_arg_get_typespec (*ss_info->data.scalar.dummy_arg).type + == BT_CLASS && ss_info->expr->ts.type == BT_CLASS) return true; @@ -11207,9 +11208,8 @@ gfc_get_proc_ifc_for_expr (gfc_expr *procedure_ref) gfc_ss * gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, - gfc_symbol *proc_ifc, gfc_ss_type type) + gfc_ss_type type) { - gfc_formal_arglist *dummy_arg; int scalar; gfc_ss *head; gfc_ss *tail; @@ -11218,16 +11218,12 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, head = gfc_ss_terminator; tail = NULL; - if (proc_ifc) -dummy_arg = gfc_sym_get_dummy_args (proc_ifc); - else -dummy_arg = NULL; - scalar = 1; for (; arg; arg = arg->next) { + gfc_dummy_arg * const dummy_arg = arg->associated_dummy; if (!arg->expr || arg->expr->expr_type == EXPR_NULL) - goto loop_continue; + continue; newss = gfc_walk_subexpr (head, arg->expr); if (newss == head) @@ -11237,13 +11233,13 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, newss = gfc_get_scalar_ss (head, arg->expr); newss->info->type = type; if (dummy_arg) - newss->info->data.scalar.dummy_arg = dummy_arg->sym;
[PATCH v2 5/7] fortran: Delete redundant missing_arg_type field
Now that we can get information about an actual arg's associated dummy using the associated_dummy attribute, the field missing_arg_type contains redundant information. This removes it. gcc/fortran/ * gfortran.h (gfc_actual_arglist::missing_arg_type): Remove. * interface.c (gfc_compare_actual_formal): Remove missing_arg_type initialization. * intrinsic.c (sort_actual): Ditto. * trans-expr.c (gfc_conv_procedure_call): Use associated_dummy and gfc_dummy_arg_get_typespec to get the dummy argument type. --- gcc/fortran/gfortran.h | 5 - gcc/fortran/interface.c | 5 - gcc/fortran/intrinsic.c | 5 + gcc/fortran/trans-expr.c | 9 +++-- 4 files changed, 8 insertions(+), 16 deletions(-) diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 12dd33bf74f..5a28d1408eb 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -1155,11 +1155,6 @@ typedef struct gfc_actual_arglist /* Alternate return label when the expr member is null. */ struct gfc_st_label *label; - /* This is set to the type of an eventual omitted optional - argument. This is used to determine if a hidden string length - argument has to be added to a function call. */ - bt missing_arg_type; - gfc_param_spec_type spec_type; struct gfc_expr *expr; diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index d463ee8228a..7289374e932 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -3581,11 +3581,6 @@ gfc_compare_actual_formal (gfc_actual_arglist **ap, gfc_formal_arglist *formal, if (*ap == NULL && n > 0) *ap = new_arg[0]; - /* Note the types of omitted optional arguments. */ - for (a = *ap, f = formal; a; a = a->next, f = f->next) -if (a->expr == NULL && a->label == NULL) - a->missing_arg_type = f->sym->ts.type; - return true; } diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index c42891e7e1a..d8bf5732e0a 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -4438,10 +4438,7 @@ do_sort: } if (a == NULL) - { - a = gfc_get_actual_arglist (); - a->missing_arg_type = f->ts.type; - } + a = gfc_get_actual_arglist (); a->associated_dummy = get_intrinsic_dummy_arg (f); diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index b18a9ec9799..3e1f12bfbc7 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -5831,7 +5831,10 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, { /* Pass a NULL pointer for an absent arg. */ parmse.expr = null_pointer_node; - if (arg->missing_arg_type == BT_CHARACTER) + gfc_dummy_arg * const dummy_arg = arg->associated_dummy; + if (dummy_arg + && gfc_dummy_arg_get_typespec (*dummy_arg).type + == BT_CHARACTER) parmse.string_length = build_int_cst (gfc_charlen_type_node, 0); } @@ -5848,7 +5851,9 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, || !CLASS_DATA (fsym)->attr.allocatable)); gfc_init_se (&parmse, NULL); parmse.expr = null_pointer_node; - if (arg->missing_arg_type == BT_CHARACTER) + if (arg->associated_dummy + && gfc_dummy_arg_get_typespec (*arg->associated_dummy).type + == BT_CHARACTER) parmse.string_length = build_int_cst (gfc_charlen_type_node, 0); } else if (fsym && fsym->ts.type == BT_CLASS
[PATCH v2 6/7] Revert "Remove KIND argument from INDEX so it does not mess up scalarization."
This reverts commit d09847357b965a2c2cda063827ce362d4c9c86f2 except for its testcase. gcc/fortran/ * intrinsic.c (add_sym_4ind): Remove. (add_functions): Use add_sym4 instead of add_sym4ind. Don’t special case the index intrinsic. * iresolve.c (gfc_resolve_index_func): Use the individual arguments directly instead of the full argument list. * intrinsic.h (gfc_resolve_index_func): Update the declaration accordingly. * trans-decl.c (gfc_get_extern_function_decl): Don’t modify the list of arguments in the case of the index intrinsic. --- gcc/fortran/intrinsic.c | 48 ++-- gcc/fortran/intrinsic.h | 3 ++- gcc/fortran/iresolve.c | 21 -- gcc/fortran/trans-decl.c | 24 +--- 4 files changed, 14 insertions(+), 82 deletions(-) diff --git a/gcc/fortran/intrinsic.c b/gcc/fortran/intrinsic.c index d8bf5732e0a..5cd4225762b 100644 --- a/gcc/fortran/intrinsic.c +++ b/gcc/fortran/intrinsic.c @@ -888,39 +888,6 @@ add_sym_4 (const char *name, gfc_isym_id id, enum klass cl, int actual_ok, bt ty (void *) 0); } -/* Add a symbol to the function list where the function takes 4 - arguments and resolution may need to change the number or - arrangement of arguments. This is the case for INDEX, which needs - its KIND argument removed. */ - -static void -add_sym_4ind (const char *name, gfc_isym_id id, enum klass cl, int actual_ok, - bt type, int kind, int standard, - bool (*check) (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *), - gfc_expr *(*simplify) (gfc_expr *, gfc_expr *, gfc_expr *, - gfc_expr *), - void (*resolve) (gfc_expr *, gfc_actual_arglist *), - const char *a1, bt type1, int kind1, int optional1, - const char *a2, bt type2, int kind2, int optional2, - const char *a3, bt type3, int kind3, int optional3, - const char *a4, bt type4, int kind4, int optional4 ) -{ - gfc_check_f cf; - gfc_simplify_f sf; - gfc_resolve_f rf; - - cf.f4 = check; - sf.f4 = simplify; - rf.f1m = resolve; - - add_sym (name, id, cl, actual_ok, type, kind, standard, cf, sf, rf, - a1, type1, kind1, optional1, INTENT_IN, - a2, type2, kind2, optional2, INTENT_IN, - a3, type3, kind3, optional3, INTENT_IN, - a4, type4, kind4, optional4, INTENT_IN, - (void *) 0); -} - /* Add a symbol to the subroutine list where the subroutine takes 4 arguments. */ @@ -2223,11 +2190,11 @@ add_functions (void) /* The resolution function for INDEX is called gfc_resolve_index_func because the name gfc_resolve_index is already used in resolve.c. */ - add_sym_4ind ("index", GFC_ISYM_INDEX, CLASS_ELEMENTAL, ACTUAL_YES, - BT_INTEGER, di, GFC_STD_F77, - gfc_check_index, gfc_simplify_index, gfc_resolve_index_func, - stg, BT_CHARACTER, dc, REQUIRED, ssg, BT_CHARACTER, dc, REQUIRED, - bck, BT_LOGICAL, dl, OPTIONAL, kind, BT_INTEGER, di, OPTIONAL); + add_sym_4 ("index", GFC_ISYM_INDEX, CLASS_ELEMENTAL, ACTUAL_YES, + BT_INTEGER, di, GFC_STD_F77, + gfc_check_index, gfc_simplify_index, gfc_resolve_index_func, + stg, BT_CHARACTER, dc, REQUIRED, ssg, BT_CHARACTER, dc, REQUIRED, + bck, BT_LOGICAL, dl, OPTIONAL, kind, BT_INTEGER, di, OPTIONAL); make_generic ("index", GFC_ISYM_INDEX, GFC_STD_F77); @@ -4547,10 +4514,9 @@ resolve_intrinsic (gfc_intrinsic_sym *specific, gfc_expr *e) arg = e->value.function.actual; - /* Special case hacks for MIN, MAX and INDEX. */ + /* Special case hacks for MIN and MAX. */ if (specific->resolve.f1m == gfc_resolve_max - || specific->resolve.f1m == gfc_resolve_min - || specific->resolve.f1m == gfc_resolve_index_func) + || specific->resolve.f1m == gfc_resolve_min) { (*specific->resolve.f1m) (e, arg); return; diff --git a/gcc/fortran/intrinsic.h b/gcc/fortran/intrinsic.h index 2148f89e194..b195e0b271a 100644 --- a/gcc/fortran/intrinsic.h +++ b/gcc/fortran/intrinsic.h @@ -521,7 +521,8 @@ void gfc_resolve_ibits (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *); void gfc_resolve_ibset (gfc_expr *, gfc_expr *, gfc_expr *); void gfc_resolve_image_index (gfc_expr *, gfc_expr *, gfc_expr *); void gfc_resolve_image_status (gfc_expr *, gfc_expr *, gfc_expr *); -void gfc_resolve_index_func (gfc_expr *, gfc_actual_arglist *); +void gfc_resolve_index_func (gfc_expr *, gfc_expr *, gfc_expr *, gfc_expr *, + gfc_expr *); void gfc_resolve_ierrno (gfc_expr *); void gfc_resolve_ieor (gfc_expr *, gfc_expr *, gfc_expr *); void gfc_resolve_ichar (gfc_expr *, gfc_expr *, gfc_expr *); diff --git a/gcc/fortran/iresolve.c b/gcc/fortran/iresolve.c index e17fe45f080..598c0409b66 100644 --- a/gcc/fortran/iresolve.c +++ b/gcc/fortran/iresolve.c @@ -1276,27 +1276,16 @@ gfc_resolve_ior (gfc_expr *f, gfc_expr *i, gfc_expr *j) void -gfc_resolve_index_func (gfc_expr *f, gfc_actual_arglist *a) +gfc_resolve_index_func (gfc_expr *f, gfc_expr *str, +
[PATCH v2 7/7] fortran: Ignore unused args in scalarization [PR97896]
The KIND argument of the INDEX intrinsic is a compile time constant that is used at compile time only to resolve to a kind-specific library method. It is otherwise completely ignored at runtime, and there is no code generated for it as the library procedure has no kind argument. This confuses the scalarizer which expects to see every argument of elemental functions to be used when calling a procedure. This change removes the argument from the scalarization lists at the beginning of the scalarization process, so that the argument is completely ignored. gcc/fortran/ PR fortran/97896 * interface.c (gfc_dummy_arg_get_name): New function. * gfortran.h (gfc_dummy_arg_get_name): Declare it. * trans-array.h (gfc_get_intrinsic_for_expr, gfc_get_proc_ifc_for_expr): New. * trans-array.c (gfc_get_intrinsic_for_expr, arg_evaluated_for_scalarization): New. (gfc_walk_elemental_function_args): Add intrinsic procedure as argument. Check arg_evaluated_for_scalarization. * trans-intrinsic.c (gfc_walk_intrinsic_function): Update call. * trans-stmt.c (get_intrinsic_for_code): New. (gfc_trans_call): Update call. gcc/testsuite/ PR fortran/97896 * gfortran.dg/index_5.f90: New. --- gcc/fortran/gfortran.h| 1 + gcc/fortran/interface.c | 17 + gcc/fortran/trans-array.c | 51 ++- gcc/fortran/trans-array.h | 3 ++ gcc/fortran/trans-intrinsic.c | 1 + gcc/fortran/trans-stmt.c | 20 +++ gcc/testsuite/gfortran.dg/index_5.f90 | 23 7 files changed, 115 insertions(+), 1 deletion(-) create mode 100644 gcc/testsuite/gfortran.dg/index_5.f90 diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 5a28d1408eb..4035d260498 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -2196,6 +2196,7 @@ struct gfc_dummy_arg #define gfc_get_dummy_arg() XCNEW (gfc_dummy_arg) +const char * gfc_dummy_arg_get_name (gfc_dummy_arg &); const gfc_typespec & gfc_dummy_arg_get_typespec (gfc_dummy_arg &); bool gfc_dummy_arg_is_optional (gfc_dummy_arg &); diff --git a/gcc/fortran/interface.c b/gcc/fortran/interface.c index 7289374e932..22aa916c88e 100644 --- a/gcc/fortran/interface.c +++ b/gcc/fortran/interface.c @@ -5400,6 +5400,23 @@ gfc_get_formal_from_actual_arglist (gfc_symbol *sym, } +const char * +gfc_dummy_arg_get_name (gfc_dummy_arg & dummy_arg) +{ + switch (dummy_arg.kind) +{ +case GFC_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.intrinsic->name; + +case GFC_NON_INTRINSIC_DUMMY_ARG: + return dummy_arg.u.non_intrinsic->sym->name; + +default: + gcc_unreachable (); +} +} + + const gfc_typespec & gfc_dummy_arg_get_typespec (gfc_dummy_arg & dummy_arg) { diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 6ae72a354e5..96b0a2583b0 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -11201,6 +11201,51 @@ gfc_get_proc_ifc_for_expr (gfc_expr *procedure_ref) } +/* Given an expression referring to an intrinsic function call, + return the intrinsic symbol. */ + +gfc_intrinsic_sym * +gfc_get_intrinsic_for_expr (gfc_expr *call) +{ + if (call == NULL) +return NULL; + + /* Normal procedure case. */ + if (call->expr_type == EXPR_FUNCTION) +return call->value.function.isym; + else +return NULL; +} + + +/* Indicates whether an argument to an intrinsic function should be used in + scalarization. It is usually the case, except for some intrinsics + requiring the value to be constant, and using the value at compile time only. + As the value is not used at runtime in those cases, we donât produce code + for it, and it should not be visible to the scalarizer. */ + +static bool +arg_evaluated_for_scalarization (gfc_intrinsic_sym *function, + gfc_dummy_arg *dummy_arg) +{ + if (function != NULL && dummy_arg != NULL) +{ + switch (function->id) + { + case GFC_ISYM_INDEX: + if (strcmp ("kind", gfc_dummy_arg_get_name (*dummy_arg)) == 0) + return false; + /* Fallthrough. */ + + default: + break; + } +} + + return true; +} + + /* Walk the arguments of an elemental function. PROC_EXPR is used to check whether an argument is permitted to be absent. If it is NULL, we don't do the check and the argument is assumed to be present. @@ -11208,6 +11253,7 @@ gfc_get_proc_ifc_for_expr (gfc_expr *procedure_ref) gfc_ss * gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, + gfc_intrinsic_sym *intrinsic_sym, gfc_ss_type type) { int scalar; @@ -11222,7 +11268,9 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg, for (; arg; arg = arg->next) { gfc_dummy_arg * const dummy_arg = arg->associated_dummy; - if (!arg->expr || arg->expr->expr_type == EXPR_NULL) + if (!arg->expr +
Re: [RFC, Fortran] Fix c_float128 and c_float128_complex on targets with 128-bit long double.
On Wed, Aug 04, 2021 at 02:14:07PM -0600, Sandra Loosemore wrote: > I was trying last week to run my not-yet-committed TS29113 testsuite > on a powerpc64le-linux-gnu target and ran into some problems with > the kind constants c_float128 and c_float128_complex from the > ISO_C_BINDING module; per the gfortran manual they are supposed to > represent the kind of the gcc extension type __float128 and the > corresponding complex type. They were being set to -4 (e.g., not > supported) instead of 16, although this target does define > __float128 and real(16) is accepted as a supported type by the > Fortran front end. > > Anyway, the root of the problem is that the definition of these > constants only looked at gfc_float128_type_node, which only gets set > if TFmode is not the same type as long_double_type_node. I > experimented with setting gfc_float128_type_node = > long_double_type_node but that caused various Bad Things to happen > elsewhere in code that expected them to be distinct types, so I > ended up with this minimally intrusive patch that only tweaks the > definitions of the c_float128 and c_float128_complex constants. > > I'm not sure this is completely correct, though. I see PowerPC > supports 2 different 128-bit encodings and it looks like TFmode/long > double is mapped onto the one selected by the ABI and/or > command-line options; that's the only one the Fortran front end > knows about. All of TFmode, IFmode, and KFmode would map onto kind > 16 anyway (in spite of having different TYPE_PRECISION values) so > Fortran wouldn't be able to distinguish them. The thing that > confuses me is how/when the rs6000 backend defines __float128; it > looks like the documentation in the GCC manual doesn't agree with > the code, and I'm not sure what the intended behavior really is. Is > it possible that __float128 could end up defined but specifying a > different type than TFmode, and if so is there a target-independent > way to identify that situation? Can the PowerPC experts help > straighten me out? > > -Sandra At the moment, we only fully support C and C++ when changing the long double format (between IEEE 128-bit, IBM 128-bit, and 64-bit) when the compiler is invoked (and assuming you are using GLIBC 2.32 or newer). For Fortran and the other languages, the only way to change the floating point format is to configure the compiler with the '--with-long-double-format=ieee' configuration option. This makes TFmode use IEEE 128-bit floating point instead of IBM 128-bit floating point. It would take somebody familar with the Fortran front end and libraries to make the same sort of modifications that were made for the C and C++ languages. Basically you need build libgfortran so that it has support for both floating point formats, using different names. You would need to modify the fortran front end to call the alternate functions when the switch is used to change the floating point format. It might be nice to have a Fortran specific way to specify which of the two floating point formats are used for REAL*16 (similar to the use of __float128 and __ibm128 in C/C++, and also _Float128 in just C). If you are going to do it, good luck. FWIW, I have built GCC compilers with the alternate floating point format, and I've been able to run the test suite and compile the Spec 2017 test suite with it. Generally to build a bootstrap compiler with the alternate long double representation I go through the following steps. 1) Make sure you have a GLIBC that supports switching long double representation (2.32 or new). I tend to use the IBM Advance Toolchain AT 14.0-3 to provide the new library, but if the native GLIBC on your system is new enough you could use that. I've discovered that there are problems if the GCC zlib is use, so I use the system zlib. The options I use when configuring the compiler include: --with-advance-toolchain=at14.0 --with-system-zlib --with-native-system-header-dir=/opt/at14.0/include If you are building and running on a power9 system, it is helpful if you add the option to set the default CPU to power9, since that way the compiler will automatically use the hardware IEEE 128-bit instructions that were added in power9. Otherwise it has to go through a call to do each operation. If you are running on a power9, we use the ifunc attribute to select modules that are built to use the hardware instruction. --with-cpu=power9 2) Build a non-bootstrap compiler with the '--with-long-double-format=ieee' configuration option, and install it somewhere. 3) With the compiler built in step #2, build the three libraries GCC uses (MPC, MPFR, and GMP), and install them some place. You need to do this because these libraries have functions in them with long double arguments. GCC doesn't actually use the functions with the long double arguments, but you will get a linker warning about mixing long double floating point type. 4) With the compiler built in step #2 a
Re: [RFC, Fortran] Fix c_float128 and c_float128_complex on targets with 128-bit long double.
On 8/5/21 11:33 AM, Michael Meissner wrote: At the moment, we only fully support C and C++ when changing the long double format (between IEEE 128-bit, IBM 128-bit, and 64-bit) when the compiler is invoked (and assuming you are using GLIBC 2.32 or newer). For Fortran and the other languages, the only way to change the floating point format is to configure the compiler with the '--with-long-double-format=ieee' configuration option. This makes TFmode use IEEE 128-bit floating point instead of IBM 128-bit floating point. My understanding from reading the code is is that for GNU/Linux targets, PowerPC already defaults to the IEEE format for TFmode? I'm not sure what targets the IBM format might be the default on. It would take somebody familar with the Fortran front end and libraries to make the same sort of modifications that were made for the C and C++ languages. Basically you need build libgfortran so that it has support for both floating point formats, using different names. You would need to modify the fortran front end to call the alternate functions when the switch is used to change the floating point format. It might be nice to have a Fortran specific way to specify which of the two floating point formats are used for REAL*16 (similar to the use of __float128 and __ibm128 in C/C++, and also _Float128 in just C). If you are going to do it, good luck. Well, I am actually not at all interested in doing that. My questions for the PowerPC experts are: (1) When is the __float128 type defined, and which format does it specify? Is it always the IEEE format, or does it specify the same format as TFmode/long double? (2) If __float128 is not always the same 128-bit format as TFmode/long double, how can I detect that in the Fortran front end in a target-independent way? Is it possible without adding a new target hook? (3) Can we do anything about the "Additional Floating Types" section in extend.texi? It's not clear on the answer to (1), and I think the stuff about "future versions of GCC" is bit-rotten as it goes back to at least GCC 6. (Either it's been implemented by now, or the idea was discarded.) Basically, I want the Fortran front end to define c_float128 to 16 if C supports __float128 and it corresponds to TFmode, otherwise it ought to continue to define c_float128 to -4. I do not want to make the Fortran front end support multiple 128-bit encodings at the same time, just accurately define c_float128. -Sandra
Re: [RFC, Fortran] Fix c_float128 and c_float128_complex on targets with 128-bit long double.
On Thu, Aug 05, 2021 at 12:19:37PM -0600, Sandra Loosemore wrote: > On 8/5/21 11:33 AM, Michael Meissner wrote: > >At the moment, we only fully support C and C++ when changing the long double > >format (between IEEE 128-bit, IBM 128-bit, and 64-bit) when the compiler is > >invoked (and assuming you are using GLIBC 2.32 or newer). > > > >For Fortran and the other languages, the only way to change the floating > >point > >format is to configure the compiler with the '--with-long-double-format=ieee' > >configuration option. This makes TFmode use IEEE 128-bit floating point > >instead of IBM 128-bit floating point. > > My understanding from reading the code is is that for GNU/Linux > targets, PowerPC already defaults to the IEEE format for TFmode? > I'm not sure what targets the IBM format might be the default on. All PowerPC systems that I'm aware of that use 128-bit floating point use the IBM format. It is anticipated that one or more Linux distributions in the future may move to IEEE 128-bit format, but right now, I'm not aware that any have moved. > >It would take somebody familar with the Fortran front end and libraries to > >make > >the same sort of modifications that were made for the C and C++ languages. > >Basically you need build libgfortran so that it has support for both floating > >point formats, using different names. You would need to modify the fortran > >front end to call the alternate functions when the switch is used to change > >the > >floating point format. It might be nice to have a Fortran specific way to > >specify which of the two floating point formats are used for REAL*16 (similar > >to the use of __float128 and __ibm128 in C/C++, and also _Float128 in just > >C). > > > >If you are going to do it, good luck. > > Well, I am actually not at all interested in doing that. My > questions for the PowerPC experts are: > > (1) When is the __float128 type defined, and which format does it > specify? Is it always the IEEE format, or does it specify the same > format as TFmode/long double? __float128 (and _Float128 in C) is always IEEE 128-bit, if IEEE 128-bit is supported. By default, IEEE 128-bit is only supported on little endian PowerPC 64-bit systems. For C (but not C++), you can declare constants with the f128 suffix so that they would be compatible with the _Float128 type. > > (2) If __float128 is not always the same 128-bit format as > TFmode/long double, how can I detect that in the Fortran front end > in a target-independent way? Is it possible without adding a new > target hook? You can look at the constants in float.h: For a system with IBM long double: FLT_RADIX= 2 LDBL_MANT_DIG= 106 LDBL_DIG = 31 LDBL_MIN_EXP = -968 LDBL_MIN_10_EXP = -291 LDBL_MAX_EXP = 1024 LDBL_MAX_10_EXP = 308 For a system with IEEE long double: FLT_RADIX= 2 LDBL_MANT_DIG= 113 LDBL_DIG = 33 LDBL_MIN_EXP = -16381 LDBL_MIN_10_EXP = -4931 LDBL_MAX_EXP = 16384 LDBL_MAX_10_EXP = 4932 For a system that uses 64-bit numbers for long double: FLT_RADIX= 2 LDBL_MANT_DIG= 53 LDBL_DIG = 15 LDBL_MIN_EXP = -1021 LDBL_MIN_10_EXP = -307 LDBL_MAX_EXP = 1024 LDBL_MAX_10_EXP = 308 In addition, the PowerPC GCC defines __LONG_DOUBLE_IEEE128__ if long double is IEEE 128-bit, and __LONG_DOUBLE_IBM128__ if long double IBM 128-bit. If long double is 64-bit, the macro __LONG_DOUBLE_128__ is not defined. > (3) Can we do anything about the "Additional Floating Types" section > in extend.texi? It's not clear on the answer to (1), and I think > the stuff about "future versions of GCC" is bit-rotten as it goes > back to at least GCC 6. (Either it's been implemented by now, or > the idea was discarded.) > > Basically, I want the Fortran front end to define c_float128 to 16 > if C supports __float128 and it corresponds to TFmode, otherwise it > ought to continue to define c_float128 to -4. I do not want to make > the Fortran front end support multiple 128-bit encodings at the same > time, just accurately define c_float128. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.ibm.com, phone: +1 (978) 899-4797