- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Dear Support,
We use Intel oneAPI 2023.2.0 on Windows/Linux and have found a compiler bug.
Please see the attached zip file for a reproducer. (includes the source code, compiler options, and disassembly outputs)
ifx does wrong optimization with -O3 but correct optimization with -O1 option.
ifort does it correct regardless of -O3 or -O1
Also our big pool of legacy fortran77 code with a lot of regressiontest run bit identical on both compilers ifort and ifx in debug mode.
It would be nice if this bug can be fixed so that we can transit from ifort to ifx in the future.
Thanks in advance and best regards
Frank
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I discussed this issue with the team, and we won't 'fix' it since it is undefined behavior.
The work around of declaring the array with size two might also break in the future, however, the recommendation is to stick with that for now.
If the program flow is always like this:
integer*8 add,off
integer array(1)
#c routine for memory allocation
call allocation(add,off,array)
#work with array
call func(array(1+off))
#c routine to free memory
free(add)
so only performance relevant operations are done inside func, you can add asynchronous without performance impact since inside func you don't need to add the attribute.
Another way would be do call a dummy function dummy(intarr) between each assignment, or just simply put all the assignments inside another function, but again those workarounds require the optimizer not seeing the declaration of intarr(1).
Link Copied
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Frank,
unfortunately, I don't think this is valid code.
Even the Fortran66 standard says:
Page 17.:
No array element name may contain a subscript that, during execution of the executable program, assumes a value less than one or larger than the maximum length specified in the array declarator.
https://archive.org/details/ansi-x-3.9-1966-fortran-66/page/16/mode/2up
You can add volatile or asynchronous to the intarr declaration which prevent optimizations on intarr.
Best
Tobias
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi,
Thank you for your reply. We use classic Intel Fortran compiler ifort over 20 years now and our code base is a huge amount of Fortran77 files. On Linux and Windows we used the following trick to dynamically allocate memory.
integer*8 add,off
integer array(1)
#c routine for memory allocation
call allocation(add,off,array)
#work with array
call func(array(1+off))
#c routine to free memory
free(add)
We never had a problem with this construction concerning ifort on Windows and Linux.
Also ifx does this right (as ifort) in many locations in our code, but sometimes it optimizes things away with O3 like in the example I gave.
Even with intarr(2) it does work with ifx!
Why is ifx not consistent with ifort?
How can we safely use volatile on these arrays but also get optimization performance benefits?
Best regards
Frank
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Newer Versions of Fortran support array descriptors which permit arrays defined with negative indices. This does require the descriptor be visible.
! NegIndex.f90
module mod_foo
interface
subroutine fooA(fooarg)
real :: fooarg(:,:)
end subroutine fooA
subroutine fooB(fooarg)
real :: fooarg(:,:)
end subroutine fooB
end interface
end module mod_foo
program NegIndex
use mod_foo
implicit none
real :: array(-10:10, 3)
print *, lbound(array, 1), ubound(array, 1), size(array, 1)
call fooA(array)
call fooB(array)
end program NegIndex
subroutine fooA(arg)
use mod_foo
real :: arg(:,:)
print *, lbound(arg, 1), ubound(arg,1), size(arg, 1)
end subroutine fooA
subroutine fooB(arg)
use mod_foo
real :: arg(-10:,:)
print *, lbound(arg, 1), ubound(arg,1), size(arg, 1)
end subroutine fooB
-10 10 21
1 21 21
-10 10 21
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
your code is completely different from the code Frank uses.
You declare an array and always stay inside the declaration.
Frank's code does some C magic on the hood and changes the declaration, for the compiler it looks like out of bound access to a array of length 1 and the compiler simply removes all but the first and last assignment to this length 1 array. gfortran does the same, and I could bet NAGfortran also does the same but I have not tested it yet.
I will discuss with the developers and see if there is anything we can do.
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Then Frank needs to specify the index ranges for himself.
module mod_foo
interface
subroutine fooA(fooarg)
real :: fooarg(:,:)
end subroutine fooA
subroutine fooB(fooarg)
real :: fooarg(:,:)
end subroutine fooB
end interface
end module mod_foo
program NegIndex
use mod_foo
implicit none
real :: array(-10:10, 3)
print *, lbound(array, 1), ubound(array, 1), size(array, 1)
call fooA(array)
call fooB(array)
call fooNoInterface(array, -3, size(array, 1) - 3 - 1, size(array,2))
end program NegIndex
subroutine fooA(arg)
use mod_foo
real :: arg(:,:)
print *, lbound(arg, 1), ubound(arg,1), size(arg, 1)
end subroutine fooA
subroutine fooB(arg)
use mod_foo
real :: arg(-10:,:)
print *, lbound(arg, 1), ubound(arg,1), size(arg, 1)
end subroutine fooB
subroutine fooNoInterface(arg, lb1, ub1, sz2)
integer :: lb1, ub1, sz2
real :: arg(lb1:ub1, 0:sz2-1)
print *, lbound(arg, 1), ubound(arg,1), size(arg, 1)
end subroutine fooNoInterface
-10 10 21
1 21 21
-10 10 21
-3 17 21
Jim Dempsey
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
I discussed this issue with the team, and we won't 'fix' it since it is undefined behavior.
The work around of declaring the array with size two might also break in the future, however, the recommendation is to stick with that for now.
If the program flow is always like this:
integer*8 add,off
integer array(1)
#c routine for memory allocation
call allocation(add,off,array)
#work with array
call func(array(1+off))
#c routine to free memory
free(add)
so only performance relevant operations are done inside func, you can add asynchronous without performance impact since inside func you don't need to add the attribute.
Another way would be do call a dummy function dummy(intarr) between each assignment, or just simply put all the assignments inside another function, but again those workarounds require the optimizer not seeing the declaration of intarr(1).
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Tobias,
Thank you for your detailed answer. I think when we transit to ifx we will take the "volatile" path:
integer intarr(1)
volatile intarr
We have hundreds of code locations but I think this will fix the problem for us.
The only thing which bothers me, is that ifort and ifx do not behave the same.
Best regards
Frank
- Mark as New
- Bookmark
- Subscribe
- Mute
- Subscribe to RSS Feed
- Permalink
- Report Inappropriate Content
Hi Frank,
glad that volatile resolves your problem.
IFX is a different compiler than IFORT, so there is no guarantee that both behave the same for an undefined behavior.
Best
Tobias
- Subscribe to RSS Feed
- Mark Topic as New
- Mark Topic as Read
- Float this Topic for Current User
- Bookmark
- Subscribe
- Printer Friendly Page