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

2021-08-07 Thread Mikael Morin via Fortran
Hello,

This is a variant of the patch series previously posted for master at [1], 
without patches 1 to 5.
It has a more limited impact, which makes it more suitable for the release 
branches.

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 2 of 
the series, preceded with the revert in patch 1.  I intend to commit both of 
them squashed together.

Regression-tested on x86_64-linux-gnu.  Ok for 11 branch? 


[1] https://gcc.gnu.org/pipermail/fortran/2021-August/056317.html

Mikael Morin (2):
  Revert "Remove KIND argument from INDEX so it does not mess up
scalarization."
  fortran: Ignore unused args in scalarization [PR97896]

 gcc/fortran/intrinsic.c   | 48 +++--
 gcc/fortran/intrinsic.h   |  3 +-
 gcc/fortran/iresolve.c| 21 ++---
 gcc/fortran/trans-array.c | 61 ++-
 gcc/fortran/trans-array.h |  3 ++
 gcc/fortran/trans-decl.c  | 24 +--
 gcc/fortran/trans-intrinsic.c |  1 +
 gcc/fortran/trans-stmt.c  | 20 +
 gcc/testsuite/gfortran.dg/index_5.f90 | 23 ++
 9 files changed, 121 insertions(+), 83 deletions(-)
 create mode 100644 gcc/testsuite/gfortran.dg/index_5.f90

-- 
2.30.2



[PATCH 1/2] Revert "Remove KIND argument from INDEX so it does not mess up scalarization."

2021-08-07 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 219f04f2317..577e25a7671 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);
 
@@ -4530,10 +4497,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 2/2] fortran: Ignore unused args in scalarization [PR97896]

2021-08-07 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
* 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.  Count arguments.  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/trans-array.c | 61 ++-
 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 ++
 5 files changed, 107 insertions(+), 1 deletion(-)
 create mode 100644 gcc/testsuite/gfortran.dg/index_5.f90

diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c
index c5d61f0065c..aae79c8cbd4 100644
--- a/gcc/fortran/trans-array.c
+++ b/gcc/fortran/trans-array.c
@@ -11177,6 +11177,59 @@ 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.
+   FUNCTION is the intrinsic function being called, ACTUAL_ARG is the actual
+   argument being examined in that call, and ARG_NUM the index number
+   of ACTUAL_ARG in the list of arguments.
+   The intrinsic procedure’s dummy argument associated with ACTUAL_ARG is
+   identified using the name in ACTUAL_ARG if it is present (that is: if it’s
+   a keyword argument), otherwise using ARG_NUM.  */
+
+static bool
+arg_evaluated_for_scalarization (gfc_intrinsic_sym *function,
+ gfc_actual_arglist &actual_arg, int arg_num)
+{
+  if (function != NULL)
+{
+  switch (function->id)
+	{
+	  case GFC_ISYM_INDEX:
+	if ((actual_arg.name == NULL && arg_num == 3)
+		|| (actual_arg.name != NULL
+		&& strcmp ("kind", actual_arg.name) == 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.
@@ -11184,6 +11237,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_symbol *proc_ifc, gfc_ss_type type)
 {
   gfc_formal_arglist *dummy_arg;
@@ -11200,10 +11254,13 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg,
   else
 dummy_arg = NULL;
 
+  int arg_num = 0;
   scalar = 1;
   for (; arg; arg = arg->next)
 {
-  if (!arg->expr || arg->expr->expr_type == EXPR_NULL)
+  if (!arg->expr
+	  || arg->expr->expr_type == EXPR_NULL
+	  || !arg_evaluated_for_scalarization (intrinsic_sym, *arg, arg_num))
 	goto loop_continue;
 
   newss = gfc_walk_subexpr (head, arg->expr);
@@ -11236,6 +11293,7 @@ gfc_walk_elemental_function_args (gfc_ss * ss, gfc_actual_arglist *arg,
 }
 
 loop_continue:
+  arg_num++;
   if (dummy_arg != NULL)
 	dummy_arg = dummy_arg->next;
 }
@@ -11296,6 +11354,7 @@ gfc_walk_function_expr (gfc_ss * ss, gfc_expr * expr)
 
   ss = gfc_walk_elemental_function_args (old_ss,
 	 expr->value.function.actual,
+	 gfc_get_intrinsic_for_expr (expr),
 	 gfc_get_proc_ifc_for_expr (expr),
 	 GFC_SS_REFERENCE);
   if (ss != old_ss
diff --git a/gcc/fortran/trans-array.h b/gcc/fortran/trans-array.h
in