Search code examples
fortrandynamic-memory-allocation

Memory location of Fortran allocatable arrays on assigment?


Suppose I have something like:

real, dimension(:), allocatable :: S
integer, dimension(:) :: idx
...
S = S(idx)

where S and idx are properly allocated/initialized before the assignment.

What does the Fortran standard(s) say, if anything, about the memory location (address) of S? Should it stay in the same place after the assigment? Is it unspecified (up to the compiler to decide)? Does it make a difference if S is not allocatable?

Full example:

$ cat test.f90 
program test
implicit none
real, dimension(:), allocatable :: S
integer :: i, idx(7) = [1,3,5,7,2,4,6]

allocate(S(size(idx)))
do i=1,size(S)
  S(i) = i*i
end do

write(6,*) S
write(6,*) loc(S)

S = S(idx)

write(6,*) S
write(6,*) loc(S)

S(:) = S(idx)

write(6,*) S
write(6,*) loc(S)

deallocate(S)

end program

$ sunf90 -V
f90: Studio 12.6 Fortran 95 8.8 Linux_i386 2017/05/30

$ sunf90 test.f90 ; ./a.out 
 1.0 4.0 9.0 16.0 25.0 36.0 49.0
 37518752
 1.0 9.0 25.0 49.0 4.0 16.0 36.0
 37519840
 1.0 25.0 4.0 36.0 9.0 49.0 16.0
 37519840

(assuming loc gives something related to the address of the array)


Solution

  • In your example, it matters whether idx has the same extent (number of elements) as S. If it does, then the shape of S(idx) is the same as that of S and the standard says that no reallocation of S occurs. But if they are different, then the standard says S is deallocated, then reallocated to the shape of S(idx). If this deallocation/reallocation occurs, it is unpredictable (and probably unlikely) if the base address remains the same.

    You then asked what if S was not allocatable - in this case, the shapes must match and it's just a copy of data, though possibly via a temporary array since there is overlap.

    -- Edit August 24, 2019 --

    I polled the J3 (US Fortran standards committee) email list on this. The consensus was that, in the absence of TARGET, the "changing address" was standard-conforming, though more than one member questioned whether it was a good idea. The compiler developers evidently feel that allocating new storage and doing a single copy is faster than keeping the same storage and doing two copies (one to a temp and then one back to S.) I might see this as beneficial if a lot of data was being copied - maybe - but not in smaller cases.

    In any event you can, as you discovered, disable this behavior by giving S the TARGET attribute.