[PATCH v2 0/7] fortran: Ignore unused arguments for scalarisation [PR97896]

2021-08-05 Thread Mikael Morin via Fortran
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

2021-08-05 Thread Mikael Morin via Fortran

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

2021-08-05 Thread Mikael Morin via Fortran

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

2021-08-05 Thread Mikael Morin via Fortran

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

2021-08-05 Thread Mikael Morin via Fortran

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

2021-08-05 Thread Mikael Morin via Fortran

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."

2021-08-05 Thread Mikael Morin via Fortran

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]

2021-08-05 Thread Mikael Morin via Fortran

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.

2021-08-05 Thread Michael Meissner via Fortran
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.

2021-08-05 Thread Sandra Loosemore

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.

2021-08-05 Thread Michael Meissner via Fortran
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