I have a question,
Does using Assumed-Shape Arrays slow down a function/subroutine?
Say I have an function f1
real :: a(:)
Will this function f1 be slower than the function f2 below which put size n of a in the argument, or vice versa?
real :: a(n)
Again, my function is just for illustration and by no mean it is accurate.
I actually just wanted to ask, guys, in your experiences,
which function/subroutine do you prefer from performance point of view, f1 or f2?
Especially consider that f1 and f2 may be in a big loop and will be called many many times, in such cases f1 and f2 which is better?
Or something else?
To answer which is faster, the traditional answer is that in the assumed shape (a(:)) case the compiler passes in an array descriptor, while in the explicit shape (a(n)) the compiler passes just a pointer and dimension n as an argument. Depending on how you call it, things might or might not be faster. Also in tight loops the compiler would inline the function so there shouldn’t be any difference.
Conclusion: if performance matters, then the function should be inlined in the loop, in which case both are probably equivalent. If performance does not matter, then the performance might slightly differ, e.g., if you are passing strided arrays, then explicit shape might be faster, if you are passing contiguous arrays that somehow do not have an array descriptor in the caller (such as another subroutine with explicit shape), then the explicit shape might be slightly faster.
Our plan with LFortran is to do things like function inlining at the ASR level, and be able to print it as Fortran source code, so that one can check what exactly the compiler is doing and ensure optimal code is generated (inlined in this case). Currently we decided to pass an array descriptor for all arrays, including explicit shape. We will experiment with different approaches later.
The situation is really YMMV depending on the processor, any attempt at any generalization can be legitimately challenged.
But my experience suggests any performance difference in terms of assumed-shape vis-a-vis other options (assumed size, explicit shape, etc,) is likely going to be small, so much so that overlooking the benefits of assumed-shape for such gains will be akin to penny wise, pound foolish.
real(dp), intent(out) :: r(:)
integer :: n, i
n = size(r)
do i = 1, n
r(i) = 1.0_dp / i**2
end subroutine f
If an array A, start from, say, index -100. Then I put A into f(A), will f(A) crash?
Or, is it that, no matter what A’s index begins from, whenever we do f(A), f automatically convert A into r, such that r’s index is from 1, so the actual index A does not matter?
Sorry this is really a lazy question and I should actually try it myself. Just curious