Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
29236 Discussions

ifx: possible bug with offsets/bounds and -O2/-O3

ronaldorpela
Beginner
392 Views

I’ve encountered an issue in the Intel Fortran Compiler (ifx) that appears to be related to how arrays with non-zero-based (offset) indices are handled under optimization flags -O2 and -O3. The problem does not occur when using -O1.


System Information

  • Compiler versions tested: 2025.1.0 and 2025.2.0
  • Processor: Intel(R) Xeon(R) W-2125 CPU
  • Optimization levels affected: -O2, -O3
  • Optimization level working correctly: -O1

The issue seems to be associated with arrays declared using non-default lower bounds (e.g., A(-lmax:lmax, -lmax:lmax, lmax)). When compiled with -O2 or -O3, certain assignments to such arrays do not appear to take effect, even though they execute correctly with -O1.

In particular, assignments to A(0, 0, l) in subroutine test1 do not persist in the output when the array is allocated with non-zero lower bounds. The same logical behavior implemented with default (1-based) indexing in test2 or handled via a separate subroutine in test3 produces correct results across all optimization levels.

Code

module m
  implicit none
  private
  public :: test1, test2, test3
  complex(8), parameter :: zzero = (0d0, 0d0)
  complex(8), parameter :: zone = (1d0, 0d0)
  
contains
  subroutine test1(lmax, A)
    integer, intent(in) :: lmax
    complex(8), allocatable, intent(out) :: A(:,:,:)

    integer :: l

    allocate(A(-lmax:lmax, -lmax:lmax, lmax), source = zzero)
    print *, "test1"
    do l = 1, lmax
      A(0, 0, l) = zone
    end do
    call print_matrix( lmax, A )
  end subroutine test1

  subroutine test2(lmax, A)
    integer, intent(in) :: lmax
    complex(8), allocatable, intent(out) :: A(:,:,:)

    integer :: l, m

    allocate(A(2*lmax+1, 2*lmax+1, lmax), source = zzero)
    print *, "test2"
    m = lmax+1
    do l = 1, lmax
      A(m, m, l) = zone
    end do
    call print_matrix( lmax, A )
  end subroutine

  subroutine test3(lmax, A)
    integer, intent(in) :: lmax
    complex(8), allocatable, intent(out) :: A(:,:,:)

    allocate(A(-lmax:lmax, -lmax:lmax, lmax), source = zzero)
    print *, "test3"
    call fill_matrix( lmax, A )
    call print_matrix( lmax, A )
  end subroutine

  subroutine fill_matrix( lmax, A )
    integer, intent(in) :: lmax
    complex(8), intent(inout) :: A(:, :, :)

    integer :: l, m
    m = lmax+1
    do l = 1, lmax
      A(m, m, l) = zone
    end do
  end subroutine

  subroutine print_matrix( lmax, A )
    integer, intent(in) :: lmax
    complex(8), intent(in) :: A(-lmax:, -lmax:, :)

    print *, 'A(0, 0, 1:2):', A(0, 0, 1), A(0, 0, 2)
    print *, 'A(-2, 0, 2):', A(-2, 0, 2)
  end subroutine
end module

program  main
  use m, only: test1, test2, test3
  implicit none
  complex(8), allocatable :: A(:, :, :)

  call test1(2, A)
  call test2(2, A)
  call test3(2, A)
  
end program  main

Output with -O2 / -O3

test1
 A(0, 0, 1:2): (0.000000000000000E+000,0.000000000000000E+000)
 (0.000000000000000E+000,0.000000000000000E+000)
 A(-2, 0, 2): (1.00000000000000,0.000000000000000E+000)
 test2
 A(0, 0, 1:2): (1.00000000000000,0.000000000000000E+000)
 (1.00000000000000,0.000000000000000E+000)
 A(-2, 0, 2): (0.000000000000000E+000,0.000000000000000E+000)
 test3
 A(0, 0, 1:2): (1.00000000000000,0.000000000000000E+000)
 (1.00000000000000,0.000000000000000E+000)
 A(-2, 0, 2): (0.000000000000000E+000,0.000000000000000E+000)

Expected Output (with -O1)

 test1
 A(0, 0, 1:2): (1.00000000000000,0.000000000000000E+000)
 (1.00000000000000,0.000000000000000E+000)
 A(-2, 0, 2): (0.000000000000000E+000,0.000000000000000E+000)
 test2
 A(0, 0, 1:2): (1.00000000000000,0.000000000000000E+000)
 (1.00000000000000,0.000000000000000E+000)
 A(-2, 0, 2): (0.000000000000000E+000,0.000000000000000E+000)
 test3
 A(0, 0, 1:2): (1.00000000000000,0.000000000000000E+000)
 (1.00000000000000,0.000000000000000E+000)
 A(-2, 0, 2): (0.000000000000000E+000,0.000000000000000E+000)

 

The behavior in test1 suggests that array indexing with negative or zero-based bounds might be misinterpreted or mishandled during optimization. In contrast, test2 uses an array starting at index 1 (by offsetting with m = lmax + 1), and test3 isolates the update in a separate subroutine — both of which behave correctly at all optimization levels.

Labels (2)
0 Kudos
0 Replies
Reply