Am 25.04.2015 um 20:12 schrieb Mikael Morin:

> I've double-checked in the standard, and it seems it is not possible to
> simplify after all:
> 
>       If ARRAY is a whole array and either ARRAY is an assumed-size
>       array of rank DIM or dimension DIM of ARRAY has nonzero extent,
>       LBOUND (ARRAY, DIM) has a value equal to the lower bound for
>       subscript DIM of ARRAY. Otherwise the result value is 1.
> 
> We can't tell whether the array is zero-sized, so we can't tell the
> lbound value.

So it is only possible to simplify LBOUND if the lower bound is
equal to one, both for assumed-shape and explicit-shape arrays...
OK.

The attached patch does that, including a test case which catches
that particular case.

> As you may want to simplify in the limited scope of the matmul inlining,
> I'm giving comments about the patch (otherwise you can ignore them):
>  - No need to check for allocatable or pointer, it should be excluded by
> as->type == AS_ASSUMED_SHAPE (but does no harm either).

Actually, no.  You can have assumed-shape allocatable or pointer
dummy arguments which keep their original lbound; see the subroutine
'bar' in the test case.

>  - Please modify the early return condition:
>      if (as && (as->type == AS_DEFERRED || as->type == AS_ASSUMED_SHAPE
>               || as->type == AS_ASSUMED_RANK))
>        return NULL;
>    and let the existing code do the simplification work.

That is not part of my patch.

> Or drop the lbound simplification idea, and fetch the lbound "by hand"
> at matmul inline time.

I will probably do so as a future optimization, but I think that most
people will see no reason for using different lower bounds, so it is
OK for the time being to (slightly) pessimize this case.

So... here is the new patch.  OK for trunk?

        Thomas

2015-04-25  Thomas Koenig  <tkoe...@gcc.gnu.org>

        PR fortran/37131
        * simplify.c (simplify_bound): Get constant lower bounds of one
        from array spec for assumed and explicit shape shape arrays if
        the lower bounds are indeed one.

2015-04-25  Thomas Koenig  <tkoe...@gcc.gnu.org>

        PR fortran/37131
        * gfortran.dg/coarray_lib_this_image_2.f90:  Adjust
        scan pattern.
        * gfortran.dg/bound_9.f90:  New test case.

P.S:

In an earlier version, I also added

Index: trans-array.c
===================================================================
--- trans-array.c       (Revision 222431)
+++ trans-array.c       (Arbeitskopie)
@@ -5693,6 +5693,7 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sy
             to being zero size.  */
          tmp = fold_build2_loc (input_location, GE_EXPR, boolean_type_node,
                                 stride, gfc_index_zero_node);
+         tmp = gfc_likely (tmp, PRED_FORTRAN_SIZE_ZERO);
          tmp = fold_build3_loc (input_location, COND_EXPR,
                                 gfc_array_index_type, tmp,
                                 stride, gfc_index_zero_node);

but that caused the condition to always return true.  I haven't figured
out why, but either I am misunderstanding something here, or gfc_likely
is buggy, or both.

Index: simplify.c
===================================================================
--- simplify.c	(Revision 222431)
+++ simplify.c	(Arbeitskopie)
@@ -3445,6 +3445,39 @@ simplify_bound (gfc_expr *array, gfc_expr *dim, gf
 
  done:
 
+  /* If the array shape is assumed shape or explicit, we can simplify lbound
+     to 1 if the given lower bound is one because this matches what lbound
+     should return for an empty array.  */
+
+  if (!upper && as && dim && dim->expr_type == EXPR_CONSTANT
+      && (as->type == AS_ASSUMED_SHAPE || as->type == AS_EXPLICIT) 
+      && ref->u.ar.type != AR_SECTION)
+    {
+      /* Watch out for allocatable or pointer dummy arrays, they can have
+	 lower bounds that are not equal to one.  */
+      if (!(array->symtree && array->symtree->n.sym
+	    && (array->symtree->n.sym->attr.allocatable
+		|| array->symtree->n.sym->attr.pointer)))
+	{
+	  unsigned long int ndim;
+	  gfc_expr *lower, *res;
+
+	  ndim = mpz_get_si (dim->value.integer) - 1;
+	  lower = as->lower[ndim];
+	  if (lower->expr_type == EXPR_CONSTANT
+	      && mpz_cmp_si (lower->value.integer, 1) == 0)
+	    {
+	      res = gfc_copy_expr (lower);
+	      if (kind)
+		{
+		  int nkind = mpz_get_si (kind->value.integer);
+		  res->ts.kind = nkind;
+		}
+	      return res;
+	    }
+	}
+    }
+
   if (as && (as->type == AS_DEFERRED || as->type == AS_ASSUMED_SHAPE
 	     || as->type == AS_ASSUMED_RANK))
     return NULL;
! { dg-do  run }
! { dg-options "-fdump-tree-original" }
! Check for different combinations of lbound for dummy arrays,
! stressing empty arrays.  The assignments with "one =" should
! be simplified at compile time.
module tst
  implicit none
contains
  subroutine foo (a, b, one, m)
    integer, dimension(:), intent(in) :: a
    integer, dimension (-2:), intent(in) :: b
    integer, intent(out) :: one, m
    one = lbound(a,1)
    m = lbound(b,1)
  end subroutine foo

  subroutine bar (a, b, n, m)
    integer, dimension(:), allocatable, intent(inout) :: a
    integer, dimension(:), pointer, intent(inout) :: b
    integer, intent(out) :: n, m
    n = lbound(a,1)
    m = lbound(b,1)
  end subroutine bar

  subroutine baz (a, n, m, s)
    integer, intent(in) :: n,m
    integer, intent(out) :: s
    integer, dimension(n:m) :: a
    s = lbound(a,1)
  end subroutine baz

  subroutine qux (a, s, one)
    integer, intent(in) :: s
    integer, dimension(s) :: a
    integer, intent(out) :: one
    one = lbound(a,1)
  end subroutine qux
end module tst

program main
  use tst
  implicit none
  integer, dimension(3), target :: a, b
  integer, dimension(0) :: empty
  integer, dimension(:), allocatable :: x
  integer, dimension(:), pointer :: y
  integer :: n,m
  

  call foo(a,b,n,m)
  if (n .ne. 1 .or. m .ne. -2) call abort
  call foo(a(2:0), empty, n, m)
  if (n .ne. 1 .or. m .ne. 1) call abort
  call foo(empty, a(2:0), n, m)
  if (n .ne. 1 .or. m .ne. 1) call abort
  allocate (x(0))
  call bar (x, y, n, m)
  if (n .ne. 1 .or. m .ne. 1) call abort

  call baz(a,3,2,n)
  if (n .ne. 1) call abort

  call baz(a,2,3,n)
  if (n .ne. 2) call abort

  call qux(a, -3, n)
  if (n .ne. 1) call abort
end program main
! { dg-final { scan-tree-dump-times "\\*one = 1" 2 "original" } }
! { dg-final { cleanup-tree-dump "original" } }

Reply via email to