a concerned citizen
a concerned citizen

Reputation: 839

Does Fortran make copies of array sections passed to function/subroutine?

When passing sections of arrays to subroutines in Fortran, e.g. f(a, b, c(2:5,4:6)) (all of them 2D arrays), does the program first make a temporary copy of c, and then pass it to the subroutine (as reference, pointer, etc), or is the whole thing dynamically handled?

I am trying to convert some Fortran code to C++, and I see calls to subroutines that have sections of arrays passed as arguments. To my knowledge, C++ doesn't allow this so I tried to circumvent this in C++ like this (mat2d = std::vector<std::vector<T>>):

f(mat2d &a, mat2d &b, mat2d *a, int rows, int rows, int offsetx, int offsety) {...}

and calling as:

f(a, b, c.data(), ...)

This works but it requires the size(s), and also offsets for the cases where I want to make a generic matrix multiplication (for example). So, if Fortran first makes a copy of c(2:5,4:6) to (say) a temp(4,3) array, then I can mimic that in C++: simply make a copy to a temporary, and then pass a reference of that temporary to the function, without rows/columns/offsets. But if not... I wouldn't mind hearing other people's thoughts.


Example subroutine:

subroutine f(A, B, C)
  implicit none
  real(kind(1d0)) :: A(2,2), B(2,2), C(2,2)
  C = A*B
  return
end f

If my words are bad, maybe a picture with the real code will do? The arrays are auxfour(4,4), aux44(4,4), and Gv(2,2).

code

And here is a call, with auxp(5) and the same Gv:

code2

Full subroutine. Picture, not words.

sub

Upvotes: 3

Views: 1084

Answers (1)

It is true that the Fortran standard does not specify the details of the passing mechanism. However, because the compilers are trying to be efficient, we can say a lot about what normally happens in practice.

The Fortran standard does not specify that arguments are passed by reference, but the rules efectively require it. However, it could always be a reference to temporary copy. The reference normally means just the memory address (pointer) of the first element. That enables the perfectly valid usage when one passes only one element and references the whole array inside the subroutine/function.

In some cases the temporary copy is virtually unavoidable.

Let's consider

real :: a(10,10)

call f(a(2:5,4:6))

then if f is

subroutine f(c)
  real :: c(3,3)

then there is very little the compiler can do, the temporary copy is virtually guaranteed. The same holds for

subroutine f(c)
  real :: c(3,*)

However, for assumed shape array

subroutine f(c)
  real :: c(:,:)

that is not the case. These arguments are passed using an array descriptor and can be non-contiguous and you normally won't see temporary copies for them.

Finally, if the first dimension is complete:

real :: a(2:5,10)

call f(a(:,4:6))

the copy is not necessary either as the subarray is contiguous in memory.


Even when a temporary is not necessary, the compiler could always make it, nothing is guaranteed. But it is not very likely in practise. Compilers try to be efficient.

Upvotes: 7

Related Questions