This program should call sorti(3f) ten times, but calls it twenty. It calls it ten times for gfortran(1) and nvfortran(1). ifort version 2021.3.0.
program main
! bug: ifort calls sorti(1) twice for each invocation
implicit none
character(len=*),parameter :: x='(*(g0,1x))'
call doboth( [100,100,500,300,100,400,500,200] )
call doboth( [0,0,0,0,0] )
call doboth( [100,500,300,400,200] )
call doboth( [100,500,-300,0,400,200] )
call doboth( [600,300,200,100,0,-100,-200,-300] )
write(*,x)repeat('=',80)
contains
subroutine doboth(ints)
integer :: ints(:)
integer,allocatable :: iii(:)
iii=ints
write(*,x)repeat('=',80)
write(*,x)'INPUT',iii
iii(sorti(iii))=iii
write(*,x)'LHS ',iii
iii=iii(sorti(iii))
write(*,x)'RHS ',iii
end subroutine doboth
function sorti(ints) result(counts)
integer :: ints(:)
integer :: counts(size(ints)), i
integer, save :: calls=0
! WARNING: this sort is slow as mollasses, but if fun to write in one line
! relative sort first take account of duplicates
counts=[(count(ints(i) > ints) + count(ints(i) == ints(:i)), i=1,size(ints) )]
calls=calls+1
write(*,x)'CALLS',CALLS,'VALUES',counts
end function sorti
end program
链接已复制
That is...weird. I can reproduce it, but I don't understand it.
Weird enough I played with it a long time before posting, but I am finally convinced it is real. Since it could affect performance significantly and answers (with a procedure with side-effects ) I posted it even though I had a nagging feeling I might be missing a typo for a long time. Wanted some feedback before looking at the machine code which I am rusty at, but I ran this several times just mumbling exactly that ... weird, weird, weird. Good to know it reproduced and isn't a glitch in my machine.
program main
integer :: iii(5)
iii=[100,200,300,400,500]
iii(sorti(iii))=iii
contains
function sorti(ints) result(counts)
integer :: ints(:)
integer :: counts(size(ints))
integer, save :: calls=0
counts=[5,4,3,2,1]
calls=calls+1
write(*,'(*(g0,1x))')'CALLS',CALLS
end function sorti
end program
Did not get is smaller before. This reproduces it; but if ints(:) is changed to ints(5) or size(ints) is changed to 5 it vanishes.
No, it is not creating threads. My guess is that it has to do with the use of the sorti function on the left side of the assignment. It seems the compiler feels it has to call the function twice as part of determining the array of indexes used in the assignment. It isn't allowed to do this.
Very artificial test, but works fine with sorti on RHS. Made the test a little more dramatic so it actually causes an error
so a little easier to test with if more verbose
program main
integer :: iii(5)
iii=[100,200,300,400,500]
iii(sorti(iii))=iii
! iii=iii(sorti(iii)) ! works fine
if(all([500,400,300,200,100]/=iii))stop '<ERROR> values not in expected order'
stop '<INFO> all is well'
contains
function sorti(ints) result(counts)
integer :: ints(:)
integer :: counts(size(ints))
integer, save :: calls=0
counts=[5,4,3,2,1]
! intentionally cause overindexing error if calls.ne.0
counts=counts+calls
calls=calls+1
write(*,'(*(g0,1x))')'CALLS',CALLS
end function sorti
end program
Thank you for your report. I have escalated this to compiler engineering for further investigation.
The fix is in just released oneAPI 2023.1.0
