http://gcc.gnu.org/bugzilla/show_bug.cgi?id=48636
--- Comment #11 from Janne Blomqvist <jb at gcc dot gnu.org> 2011-04-20 18:14:20 UTC --- (In reply to comment #9) > > But do we actually do this? I did some tests a while ago, and IIRC for > > assumed > > shape dummy arguments the procedure always calculates new bounds such that > > they > > start from 1. That is, the procedure assumes that the actual argument > > descriptor may have lower bounds != 1. > > So my argument is basically that with the new descriptor it might make > > sense to > > switch the responsibility around such that it's the caller who makes sure > > that > > all lower bounds are 0 (as we must have the capability to do this anyway in > > order to call inter-operable procedures, no?) instead of the callee. > > No, the conversion is already done in the caller: > > subroutine bar(B) > interface; subroutine foo(a); integer :: a(:); end subroutine foo > end interface > integer :: B(:) > call foo(B) > end subroutine bar > > Shows: > parm.4.dim[0].lbound = 1; > [...] > foo (&parm.4); > For assumed-shape actual arguments, creating a new descriptor is actually not > needed - only for deferred shape ones - or if one does not have a full array > ref. > Cf. gfc_conv_array_parameter, which is called by gfc_conv_procedure_call. > > However, some additional calculation is also done in the the callee to > determine the stride and offset; e.g. > ubound.0 = (b->dim[0].ubound - b->dim[0].lbound) + 1; > again, if the dummy argument is not deferred-shaped (allocatable or pointer), > one actually knows that "b->dim[0].lbound" == 1. I think we have some > redundancy here -> missed optimization. Yes, there seems to be some redundancy indeed in that case. I dug up my testcase: module asstest implicit none contains subroutine assub(a, r) real, intent(in) :: a(:,:) real, intent(out) :: r r = a(42,43) end subroutine assub subroutine assub2(a, r) real, intent(in), allocatable :: a(:,:) real, intent(out) :: r r = a(42,43) end subroutine assub2 end module asstest The -fdump-tree-original tree for this module is: assub2 (struct array2_real(kind=4) & a, real(kind=4) & r) { *r = (*(real(kind=4)[0:] *) a->data)[(a->dim[0].stride * 42 + a->dim[1].stride * 43) + a->offset]; } assub (struct array2_real(kind=4) & a, real(kind=4) & r) { integer(kind=8) ubound.0; integer(kind=8) stride.1; integer(kind=8) ubound.2; integer(kind=8) stride.3; integer(kind=8) offset.4; integer(kind=8) size.5; real(kind=4)[0:D.1567] * a.0; integer(kind=8) D.1567; bit_size_type D.1568; <unnamed-unsigned:64> D.1569; { integer(kind=8) D.1566; D.1566 = a->dim[0].stride; stride.1 = D.1566 != 0 ? D.1566 : 1; a.0 = (real(kind=4)[0:D.1567] *) a->data; ubound.0 = (a->dim[0].ubound - a->dim[0].lbound) + 1; stride.3 = a->dim[1].stride; ubound.2 = (a->dim[1].ubound - a->dim[1].lbound) + 1; size.5 = stride.3 * NON_LVALUE_EXPR <ubound.2>; offset.4 = -stride.1 - NON_LVALUE_EXPR <stride.3>; D.1567 = size.5 + -1; D.1568 = (bit_size_type) size.5 * 32; D.1569 = (<unnamed-unsigned:64>) size.5 * 4; } *r = (*a.0)[(stride.1 * 42 + stride.3 * 43) + offset.4]; } So if we make sure that the caller fixes up the descriptor so that bounds are correct for assumed-shape parameters (as the TR requires for inter-operable procedures), then assub could be as simple as assub2.