4

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)

Jellby
  • 2,360
  • 3
  • 27
  • 56

2 Answers2

6

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.

Steve Lionel
  • 6,972
  • 18
  • 31
  • Even if there is no de/re-allocation, can we be _certain_ there'd be no memory address change? (It wouldn't be expected, surely, but is it strictly prohibited?) Probably one of these implicit requirement, rather than explicit? – francescalus Aug 22 '19 at 14:13
  • Thanks! I'm actually interested in the case where the shapes match, so I know it *can* at least happen without reallocation or "padding". For what it's worth, the Oracle (SunPro) compiler is reallocating (or at least changing the address) in such a case. – Jellby Aug 22 '19 at 14:54
  • Since there's no reallocation in the same-shape assignment, I can't see how there would be an address change. (I should have mentioned that reallocation also occurs if the length or kind types differ.) That would certainly be an odd behavior I'd complain to Oracle about. How certain are you that this is happening? Can you show an example with output that demonstrates it? I'd find it astonishing. As for @francescalus question, the standard has very clear words (10.2.1.3) on "Interpretation of intrinsic assignment." I would say reallocation is not allowed. – Steve Lionel Aug 22 '19 at 18:46
  • Yes, _Fortran_ reallocation would not be allowed on allocation with shape/type parameters unchanged, but if `S` is not a target or otherwise needing to be fixed in memory, is there a standard reason why `S` couldn't move in memory? It could be a valid optimization to simply point the array descriptor for `S` to a new location (such as of what would otherwise be an array temporary in the case of not-in-place copying)? Much as we wouldn't call copy-in/copy-out mechanics reallocation in the Fortran sense. (I'm asking you as you're a compiler expert, not because I think you're wrong.) – francescalus Aug 22 '19 at 21:14
  • 1
    The standard says that the assignment happens element-by-element (in no defined order). You're right that, implementation-wise, a hidden reallocation and copy could be done, and I can see a performance aspect as the "normal" way, when the sides overlap, involves two copies, but I don't see how that could be justified as conforming behavior. It's an interesting question and I will pose it to J3 and see what they say. – Steve Lionel Aug 22 '19 at 23:33
  • I've added a full example in the original question, with the `sunf90` output. `gfortran` does not change the address. – Jellby Aug 23 '19 at 07:45
  • ...and indeed, adding `target` to `S` fixes it for `sunf90` too. – Jellby Aug 23 '19 at 08:01
  • That's astonishing - especially the last case since assigning to S(:) disables reallocation. I will ask about this. – Steve Lionel Aug 23 '19 at 21:40
  • I edited my answer to show the results of my asking fellow committee members. – Steve Lionel Aug 24 '19 at 20:13
3

The Fortran standard says little about "memory locations". It does, however, have (Fortran 2018, Note 16.24):

It is expected that the implementation of allocatable objects will typically involve descriptors to locate the allocated storage

In the case of the question, though, it can be reasonably expected that no implementation will always keep S having the same address for the first element after assignment: S after the assignment may be arbitrarily larger than S before the assignment. In such cases a new allocation of memory may be required.

If S is not allocatable (strictly, of deferred length) its size won't change as a result of the assignment: however, it would be compatible (in many but not all cases) with the standard for the base address of S to move to a new location comparable to an array-temporary.

In cases where storage association is required (which does restrict the moving of variables in memory), the use of allocatable variables is heavily restricted.

francescalus
  • 30,576
  • 16
  • 61
  • 96