Re: [patch, fortran] Inline packing for array temporaries

2019-04-28 Thread Thomas Koenig

Hi Paul,


Could you provide the patch, please, or was it already posted?


Actually, no. I was so intent on providing the test cases that
I missed the patch itself :-)

Here it is.

Regards

Thomas
Index: fortran/expr.c
===
--- fortran/expr.c	(Revision 270622)
+++ fortran/expr.c	(Arbeitskopie)
@@ -5713,6 +5713,9 @@ gfc_is_simply_contiguous (gfc_expr *expr, bool str
   gfc_ref *ref, *part_ref = NULL;
   gfc_symbol *sym;
 
+  if (expr->expr_type == EXPR_ARRAY)
+return true;
+
   if (expr->expr_type == EXPR_FUNCTION)
 {
   if (expr->value.function.esym)
Index: fortran/trans-array.c
===
--- fortran/trans-array.c	(Revision 270622)
+++ fortran/trans-array.c	(Arbeitskopie)
@@ -7869,6 +7869,23 @@ array_parameter_size (tree desc, gfc_expr *expr, t
 			   *size, fold_convert (gfc_array_index_type, elem));
 }
 
+/* Helper function - return true if the argument is a pointer.  */
+ 
+static bool
+is_pointer (gfc_expr *e)
+{
+  gfc_symbol *sym;
+
+  if (e->expr_type != EXPR_VARIABLE ||  e->symtree == NULL)
+return false;
+
+  sym = e->symtree->n.sym;
+  if (sym == NULL)
+return false;
+
+  return sym->attr.pointer || sym->attr.proc_pointer;
+}
+
 /* Convert an array for passing as an actual parameter.  */
 
 void
@@ -8120,6 +8137,19 @@ gfc_conv_array_parameter (gfc_se * se, gfc_expr *
 			 "Creating array temporary at %L", >where);
 	}
 
+  /* When optmizing, we can use gfc_conv_subref_array_arg for
+	 making the packing and unpacking operation visible to the
+	 optimizers.  */
+
+  if (g77 && optimize && !optimize_size && expr->expr_type == EXPR_VARIABLE
+	  && !is_pointer (expr))
+	{
+	  gfc_conv_subref_array_arg (se, expr, g77,
+ fsym ? fsym->attr.intent : INTENT_INOUT,
+ false, fsym, proc_name, sym);
+	  return;
+	}
+
   ptr = build_call_expr_loc (input_location,
 			 gfor_fndecl_in_pack, 1, desc);
 
Index: fortran/trans-expr.c
===
--- fortran/trans-expr.c	(Revision 270622)
+++ fortran/trans-expr.c	(Arbeitskopie)
@@ -4576,8 +4576,10 @@ gfc_apply_interface_mapping (gfc_interface_mapping
an actual argument derived type array is copied and then returned
after the function call.  */
 void
-gfc_conv_subref_array_arg (gfc_se * parmse, gfc_expr * expr, int g77,
-			   sym_intent intent, bool formal_ptr)
+gfc_conv_subref_array_arg (gfc_se *se, gfc_expr * expr, int g77,
+			   sym_intent intent, bool formal_ptr,
+			   const gfc_symbol *fsym, const char *proc_name,
+			   gfc_symbol *sym)
 {
   gfc_se lse;
   gfc_se rse;
@@ -4594,7 +4596,37 @@ void
   stmtblock_t body;
   int n;
   int dimen;
+  gfc_se work_se;
+  gfc_se *parmse;
+  bool pass_optional;
 
+  pass_optional = fsym && fsym->attr.optional && sym && sym->attr.optional;
+
+  if (pass_optional)
+{
+  gfc_init_se (_se, NULL);
+  parmse = _se;
+}
+  else
+parmse = se;
+
+  if (gfc_option.rtcheck & GFC_RTCHECK_ARRAY_TEMPS)
+{
+  /* We will create a temporary array, so let us warn.  */
+  char * msg;
+
+  if (fsym && proc_name)
+	msg = xasprintf ("An array temporary was created for argument "
+			 "'%s' of procedure '%s'", fsym->name, proc_name);
+  else
+	msg = xasprintf ("An array temporary was created");
+
+  tmp = build_int_cst (logical_type_node, 1);
+  gfc_trans_runtime_check (false, true, tmp, >pre,
+			   >where, msg);
+  free (msg);
+}
+
   gfc_init_se (, NULL);
   gfc_init_se (, NULL);
 
@@ -4848,6 +4880,53 @@ class_array_fcn:
   else
 parmse->expr = gfc_build_addr_expr (NULL_TREE, parmse->expr);
 
+  if (pass_optional)
+{
+  tree present;
+  tree type;
+  stmtblock_t else_block;
+  tree pre_stmts, post_stmts;
+  tree pointer;
+  tree else_stmt;
+
+  /* Make this into
+
+	 if (present (a))
+	   {
+	  parmse->pre;
+	  optional = parse->expr;
+	   }
+ else
+	   optional = NULL;
+ call foo (optional);
+ if (present (a))
+parmse->post;
+
+  */
+
+  type = TREE_TYPE (parmse->expr);
+  pointer = gfc_create_var (type, "optional");
+  tmp = gfc_conv_expr_present (sym);
+  present = gfc_evaluate_now (tmp, >pre);
+  gfc_add_modify (>pre, pointer, parmse->expr);
+  pre_stmts = gfc_finish_block (>pre);
+
+  gfc_init_block (_block);
+  gfc_add_modify (_block, pointer, build_int_cst (type, 0));
+  else_stmt = gfc_finish_block (_block);
+
+  tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, present,
+			 pre_stmts, else_stmt);
+  gfc_add_expr_to_block (>pre, tmp);
+
+  post_stmts = gfc_finish_block (>post);
+  tmp = fold_build3_loc (input_location, COND_EXPR, void_type_node, present,
+			 post_stmts, build_empty_stmt (input_location));
+  gfc_add_expr_to_block (>post, tmp);
+
+  se->expr = 

Re: [patch, fortran] Inline packing for array temporaries

2019-04-28 Thread Dominique d'Humières
Hi Thomas,

> (Dominique, could you tell us again what the magic incantation for
> 32-bit mode is?)

I use:

time make -k -j8 check RUNTESTFLAGS="--target_board=unix'{-m32,-m64}'" > & 
check-*.log &

Dominique

Re: [patch, fortran] Inline packing for array temporaries

2019-04-28 Thread Paul Richard Thomas
Hi Thomas,

Could you provide the patch, please, or was it already posted?

Cheers

Paul

On Sun, 28 Apr 2019 at 10:46, Thomas Koenig  wrote:
>
> Hello world,
>
> going back a patch which was not included in gcc-9 because it was too
> late in the development cycle, here is a patch which, when optimizing
> and not optimizing for size, does inline packing for an argument.
> As you can see from the code and the test cases, there is provision
> for optional arguments.  It was necessary to split some test cases
> to take account for the new pack inline / pack in the library split.
>
> I did regression-testing on x86_64-pc-linux-gnu, in 64-bit mode.
> (Dominique, could you tell us again what the magic incantation for
> 32-bit mode is?)
>
> OK for trunk?  (Not for backporting)
>
> Regards
>
> Thomas
>
> 2019-04-28  Thomas Koenig  
>
>  PR fortran/88821
>  * expr.c (gfc_is_simply_contiguous): Return true for
>  an EXPR_ARRAY.
>  * trans-array.c (is_pointer): New function.
>  (gfc_conv_array_parameter): Call gfc_conv_subref_array_arg
>  when not optimizing and not optimizing for size if the formal
>  arg is passed by reference.
>  * trans-expr.c (gfc_conv_subref_array_arg): Add arguments
>  fsym, proc_name and sym.  Add run-time warning for temporary
>  array creation.  Wrap argument if passing on an optional
>  argument to an optional argument.
>  * trans.h (gfc_conv_subref_array_arg): Add optional arguments
>  fsym, proc_name and sym to prototype.
>
> 2019-04-28  Thomas Koenig  
>
>  PR fortran/88821
>  * gfortran.dg/alloc_comp_auto_array_3.f90: Add -O0 to dg-options
>  to make sure the test for internal_pack is retained.
>  * gfortran.dg/assumed_type_2.f90: Split compile and run time
>  tests into this and
>  * gfortran.dg/assumed_type_2a.f90: New file.
>  * gfortran.dg/c_loc_test_22.f90: Likewise.
>  * gfortran.dg/contiguous_3.f90: Likewise.
>  * gfortran.dg/internal_pack_11.f90: Likewise.
>  * gfortran.dg/internal_pack_12.f90: Likewise.
>  * gfortran.dg/internal_pack_16.f90: Likewise.
>  * gfortran.dg/internal_pack_17.f90: Likewise.
>  * gfortran.dg/internal_pack_18.f90: Likewise.
>  * gfortran.dg/internal_pack_4.f90: Likewise.
>  * gfortran.dg/internal_pack_5.f90: Add -O0 to dg-options
>  to make sure the test for internal_pack is retained.
>  * gfortran.dg/internal_pack_6.f90: Split compile and run time
>  tests into this and
>  * gfortran.dg/internal_pack_6a.f90: New file.
>  * gfortran.dg/internal_pack_8.f90: Likewise.
>  * gfortran.dg/missing_optional_dummy_6: Split compile and run time
>  tests into this and
>  * gfortran.dg/missing_optional_dummy_6a.f90: New file.
>  * gfortran.dg/no_arg_check_2.f90: Split compile and run time tests
>  into this and
>  * gfortran.dg/no_arg_check_2a.f90: New file.
>  * gfortran.dg/typebound_assignment_5.f90: Split compile and run
> time
>  tests into this and
>  * gfortran.dg/typebound_assignment_5a.f90: New file.
>  * gfortran.dg/typebound_assignment_6.f90: Split compile and run
> time
>  tests into this and
>  * gfortran.dg/typebound_assignment_6a.f90: New file.
>  * gfortran.dg/internal_pack_19.f90: New file.
>  * gfortran.dg/internal_pack_20.f90: New file.
>  * gfortran.dg/internal_pack_21.f90: New file.



-- 
"If you can't explain it simply, you don't understand it well enough"
- Albert Einstein


[patch, fortran] Inline packing for array temporaries

2019-04-28 Thread Thomas Koenig

Hello world,

going back a patch which was not included in gcc-9 because it was too
late in the development cycle, here is a patch which, when optimizing
and not optimizing for size, does inline packing for an argument.
As you can see from the code and the test cases, there is provision
for optional arguments.  It was necessary to split some test cases
to take account for the new pack inline / pack in the library split.

I did regression-testing on x86_64-pc-linux-gnu, in 64-bit mode.
(Dominique, could you tell us again what the magic incantation for
32-bit mode is?)

OK for trunk?  (Not for backporting)

Regards

Thomas

2019-04-28  Thomas Koenig  

PR fortran/88821
* expr.c (gfc_is_simply_contiguous): Return true for
an EXPR_ARRAY.
* trans-array.c (is_pointer): New function.
(gfc_conv_array_parameter): Call gfc_conv_subref_array_arg
when not optimizing and not optimizing for size if the formal
arg is passed by reference.
* trans-expr.c (gfc_conv_subref_array_arg): Add arguments
fsym, proc_name and sym.  Add run-time warning for temporary
array creation.  Wrap argument if passing on an optional
argument to an optional argument.
* trans.h (gfc_conv_subref_array_arg): Add optional arguments
fsym, proc_name and sym to prototype.

2019-04-28  Thomas Koenig  

PR fortran/88821
* gfortran.dg/alloc_comp_auto_array_3.f90: Add -O0 to dg-options
to make sure the test for internal_pack is retained.
* gfortran.dg/assumed_type_2.f90: Split compile and run time
tests into this and
* gfortran.dg/assumed_type_2a.f90: New file.
* gfortran.dg/c_loc_test_22.f90: Likewise.
* gfortran.dg/contiguous_3.f90: Likewise.
* gfortran.dg/internal_pack_11.f90: Likewise.
* gfortran.dg/internal_pack_12.f90: Likewise.
* gfortran.dg/internal_pack_16.f90: Likewise.
* gfortran.dg/internal_pack_17.f90: Likewise.
* gfortran.dg/internal_pack_18.f90: Likewise.
* gfortran.dg/internal_pack_4.f90: Likewise.
* gfortran.dg/internal_pack_5.f90: Add -O0 to dg-options
to make sure the test for internal_pack is retained.
* gfortran.dg/internal_pack_6.f90: Split compile and run time
tests into this and
* gfortran.dg/internal_pack_6a.f90: New file.
* gfortran.dg/internal_pack_8.f90: Likewise.
* gfortran.dg/missing_optional_dummy_6: Split compile and run time
tests into this and
* gfortran.dg/missing_optional_dummy_6a.f90: New file.
* gfortran.dg/no_arg_check_2.f90: Split compile and run time tests
into this and
* gfortran.dg/no_arg_check_2a.f90: New file.
* gfortran.dg/typebound_assignment_5.f90: Split compile and run 
time

tests into this and
* gfortran.dg/typebound_assignment_5a.f90: New file.
* gfortran.dg/typebound_assignment_6.f90: Split compile and run 
time

tests into this and
* gfortran.dg/typebound_assignment_6a.f90: New file.
* gfortran.dg/internal_pack_19.f90: New file.
* gfortran.dg/internal_pack_20.f90: New file.
* gfortran.dg/internal_pack_21.f90: New file.
! { dg-do run }
! { dg-options "-O -fdump-tree-original" }
! Test handling of the optional argument.

MODULE M1
  INTEGER, PARAMETER :: dp=KIND(0.0D0)
CONTAINS
  SUBROUTINE S1(a)
 REAL(dp), DIMENSION(45), INTENT(OUT), &
  OPTIONAL   :: a
  if (present(a)) STOP 1
  END SUBROUTINE S1
  SUBROUTINE S2(a)
  REAL(dp), DIMENSION(:, :), INTENT(OUT), &
  OPTIONAL   :: a
  CALL S1(a)
  END SUBROUTINE
END MODULE M1

USE M1
CALL S2()
END
! { dg-final { scan-tree-dump-times "optional" 4 "original" } }
! { dg-final { scan-tree-dump-not "_gfortran_internal_unpack" "original" } }
! { dg-do compile }
! { dg-options "-O -fdump-tree-original" }
! Check that internal_pack is not called with -O.
module x
  implicit none
contains
  subroutine bar(a, n)
integer, intent(in) :: n
integer, intent(in), dimension(n) :: a
print *,a
  end subroutine bar
end module x

program main
  use x
  implicit none
  integer, parameter :: n = 10
  integer, dimension(n) :: a
  integer :: i
  a = [(i,i=1,n)]
  call bar(a(n:1:-1),n)
end program main
! { dg-final { scan-tree-dump-not "_gfortran_internal_pack" "original" } }
! { dg-do compile }
! { dg-options "-Os -fdump-tree-original" }
! Check that internal_pack is called with -Os.
module x
  implicit none
contains
  subroutine bar(a, n)
integer, intent(in) :: n
integer, intent(in), dimension(n) :: a
print *,a
  end subroutine bar
end module x

program main
  use x
  implicit none
  integer, parameter :: n = 10
  integer, dimension(n) :: a
  integer :: i
  a = [(i,i=1,n)]
  call bar(a(n:1:-1),n)
end program main
! { dg-final { scan-tree-dump-times "_gfortran_internal_pack" 1 "original"