Memory location of Fortran allocatable arrays on assigment?
Asked Answered
I

2

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)

Inane answered 22/8, 2019 at 9:29 Comment(0)
R
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.

Repercussion answered 22/8, 2019 at 14:10 Comment(9)
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?Handwork
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.Inane
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 @Handwork question, the standard has very clear words (10.2.1.3) on "Interpretation of intrinsic assignment." I would say reallocation is not allowed.Repercussion
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.)Handwork
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.Repercussion
I've added a full example in the original question, with the sunf90 output. gfortran does not change the address.Inane
...and indeed, adding target to S fixes it for sunf90 too.Inane
That's astonishing - especially the last case since assigning to S(:) disables reallocation. I will ask about this.Repercussion
I edited my answer to show the results of my asking fellow committee members.Repercussion
H
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.

Handwork answered 22/8, 2019 at 9:41 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.