# legal to use an integer array as a do loop index ?

## legal to use an integer array as a do loop index ?

consider a "contrived" code segment:

program

integer :: N(3)

do N(1) = 1,5
write(*,*) N(1)
enddo

end

Shouldn't that be legal?

13 帖子 / 0 new

Not by the current rules of the language.  The do variable must be the name of a scalar.

Suppose we do this:

program
integer :: L, M

do concurrent (L=1:3000)
do M=1,3000
write(*,*) L, M
enddo
enddo
end

M is seen by all simultaneously executing threads. Will the "M" loop work?  It might by accident.

If this was openMP We would do:

program
integer :: L, M
!\$omp parallel private(M)
!\$omp do
do (L=1:3000)
do M=1,3000
write(*,*) L, M
enddo
enddo
!\$omp end do
!\$omp end parallel
end

This will give each thread it's own copy of the indexing variable M.

If Intel supported the "block" statement we could do this:

program
integer :: L
do concurrent (L=1:3000)
BLOCK
integer M
do M=1,3000
write(*,*) L, M
enddo
END BLOCK
enddo
end

The "do concurrent" statement seems incomplete.

Incomplete, how?  What would you want to do in a real program?

Steve
Quoting Terry Gerald Suppose we do this:

program
integer :: L, M

do concurrent (L=1:3000)
do M=1,3000
write(*,*) L, M
enddo
enddo
end

M is seen by all simultaneously executing threads. Will the "M" loop work?  It might by accident.

I don't think there's any room for accident here - the inner loop will "work" (as in the behaviour is well defined, though the order of output from the write may vary). M is undefined after the DO CONCURRENT construct completes.

That won't work, as noted.  What would work, and achieve the desired result, is

INTEGER, DIMENSION(3)  :: N
INTEGER  :: J
EQUIVALENCE (J, N(1))

DO J = 1,5
etc.

Also, when the above loop is enclosed within a DO CONCURRENT that the code generated may registerize the loop control variable J. Thus each thread will effectively have a private (non-interfering) copy of the loop control variable when registerization occurs. Registerization is not guaranteed though.

If you do need assurances of independent, enclosed, variables within the DO CONCURRENT then convert the body of the DO CONCURRENT loop into a subroutine.

Jim Dempsey

The code is just to illustrate a point - then a question.

integer :: L, M,
do concurrent (L=1:3)
do M=1,3
write(*,*)   L, M     ! <---  This is just dummy code - I dont care what is actually within the loop
enddo
enddo

Does each executing thread get it's own copy of M?

Or will there be only one M that is shared by all threads - each thread modifying M independently?

OpenMP directly recognizes and addresses the issue by providing the "private" clause.

Does the Fortran do concurrent construct "implicitly" handle the problem by creating L copies of M?

No, Fortran does not do that - or at least it does not specify what is to happen. When you use DO CONCURRENT, it is the programmer's responsibility to recognize that the loop bodies may be executed in any order.   In practice, at least, Intel Fortran will not parallelize this DO CONCURRENT because of dependencies.

DO CONCURRENT was not intended to be a replacement for OpenMP.  Rather, it was a replacement for FORALL. It has its uses, but is not as general as OpenMP.

I will comment that you can write:

DO CONCURRENT (L=1:3,M=1:3)

without the inner loop, which comes closer to what you're asking for.  Intel Fortran won't parallelize it due to the WRITE, as far as I can tell.

Steve

Thats disappointing.

Oh well - I'll have to keep using openMP.

Thanks Steve.

Quoting Steve Lionel (Intel) No, Fortran does not do that - or at least it does not specify what is to happen. When you use DO CONCURRENT, it is the programmer's responsibility to recognize that the loop bodies may be executed in any order.

A query to clarify - are you saying that the language doesn't specify how the compiler implements DO CONCURRENT that really is executed concurrently, or that the language doesn't specify what the example snippet does?

My take:  There's a difference between allowing for executing the loop bodies in any order and executing them concurrently, though the former is a step towards the latter.  The restrictions on modifying variables that are "in scope" in the do concurrent construct allow for any order of execution (and the example snippet meets those restrictions), but not necessarily concurrent execution, unless the processor is prepared to create private copies (or similar) of all variables that are updated by more than one iteration.  Hence I think the behaviour of the example snippet is well defined (bar the order of output records), but whether things happen in parallel is a compiler specific implementation question.

(Rather than asking about shared/private variable storage etc, perhaps the OP's question should simply be "will this be parallelised by ifort?")

DO CONCURRENT (L=1:3,M=1:3) has slightly different semantics, in that for a particular L, the increments of M might occur in any order (your print statements can be even more jumbled!).  Whether that's what the OP wants or not depends on what the OP wants or not.

(Does IO really prevent ifort from doing concurrent execution, or does the compiler just decide for that case that it is not worthwhile?)

Quoting Terry Gerald integer :: L, M,
do concurrent (L=1:3)
do M=1,3
write(*,*)   L, M     ! <---  This is just dummy code - I dont care what is actually within the loop
enddo
enddo

Does each executing thread get it's own copy of M?

You have no assureances as to M is or is not registerized. Debug mode - most likely not. Release mode with full optimization, likely however the above write may copy the register to the persistant M, and in which case you will/may experience a conflict.

As an alternative to subroutine, experiment with

do concurrent (L=1:3)
do M=1,3
write(*,*)   L, M     ! <---  This is just dummy code - I dont care what is actually within the loop
enddo
END ASSOCIATE
enddo

*** The IVF documentation is unclear as to what happens in the above scenario.
*** The Fortran standards may have addressed this issue.

Jim Dempsey