Search code examples
fortranintel-fortran

"In call to DSYEV, an array temporary was created for argument" in ifort but the related dimension is only 1


Related questions Temporary array creation and routine GEMM Warning message (402) : An array temporary created for argument

For the following Fortran code (modified from dsyev in fortran 90)

program test_dsyev   
implicit none  
integer, parameter :: dp = selected_real_kind(15, 307)
real(dp), allocatable  :: A(:,:), A2(:,:,:), work (:), w(:)  
real(dp) :: c1
integer :: i, j  
integer :: lwork, info,  n, lda  
character :: jobz, UPLO 

n=5
allocate(A(n,n))  
allocate(A2(1,n,n))  

A = 0.0_dp
c1 = 1.0_dp
do i = 1, n  
   do j = 1, n
     A(i, j) = i * c1 + j * c1  
   end do  
end do  
A2(1,:,:) = A

lda = n  
lwork = 10 * n  

jobz = 'N'
UPLO = 'U'
allocate(work(lwork))  
allocate(w(n))  
call dsyev(jobz,uplo,n,A,lda,w,work,lwork,info)  
write (*,*) w

call dsyev(jobz,uplo,n,A2(1,:,:),lda,w,work,lwork,info)
write (*,*) w
end program test_dsyev

called d.f90. ifort -mkl -warn all -check all d.f90 gives me

 -1.58312395177700      -1.465651932086313E-015  8.229374109843719E-018
  4.803282588162841E-016   31.5831239517770
forrtl: warning (406): fort: (1): In call to DSYEV, an array temporary was created for argument #4

Image              PC                Routine            Line        Source
a.out              0000000000408E86  Unknown               Unknown  Unknown
a.out              000000000040580B  Unknown               Unknown  Unknown
a.out              0000000000403812  Unknown               Unknown  Unknown
libc-2.17.so       00002B10A2A31555  __libc_start_main     Unknown  Unknown
a.out              0000000000403729  Unknown               Unknown  Unknown
  -1.58312395177700      -1.465651932086313E-015  8.229374109843719E-018

it seems the warning message is related to A2(1,:,:) and memory non-continuous. Yes, Fortran is column-major. But, the first dimension of A2 is 1. A2 should follow A2(1,1,1), A2(1,2,1),..., I mean, the first index of A2 does not play a role in memory allocation. Or am I totally wrong?


Solution

  • Let's consider a much simpler program to look at what's going on:

      implicit none
    
      integer i(1,1)
      call s(i(1,:))
    
    contains
    
      subroutine s(j)
        integer j(*)
      end subroutine s
    
    end program
    

    Compiled with -check to enable temporary copying checks we can see exactly the same warning:

    forrtl: warning (406): fort: (1): In call to S, an array temporary was created for argument #1
    

    Like the example of the question, the dummy argument has assumed size and the actual argument is an array section of the same rank, but one rank smaller than the whole array.

    The array section i(1,:) actual argument is contiguous, so perhaps there's no need for a temporary copy for the dummy j? Looking at this, ifort makes a temporary copy when i is not simply contiguous, even if it's "obviously" contiguous.1

    However, because the dummy argument j is assumed-size, we don't need to worry about passing the array section i(1,:): we can pass the whole array i, or the simply contiguous section i(:,:). We can do this because the ranks of the actual and dummy arguments do not need to match when the dummy is assumed-size (or explicit-size).

    Note that if the dummy is assumed-shape, then the ranks do need to match, but the compiler may handle the argument association by passing an array descriptor/dope instead of making a temporary copy: unlike assumed- and explicit-size array arguments, it's not necessary for an assumed-shape dummy to be contiguous. (The compiler may still make, and warn about making, a temporary copy when it decides that is beneficial, but it isn't always going to happen.)

    Finally, I am speculating that the trigger for a warning is simple contiguity (happy for someone in the know to confirm/dispute), but there's some evidence that you can avoid the runtime check warning with a simple alternative approach as here. (It makes complete sense for the copy to be made if not simply contiguous: simple contiguity is defined in a way to be easy to check.)


    1 i(1,:) is not simply contiguous, even when the first extent is 1, because of the rule of simple contiguity (F2018, 9.5.4):

    no subscript-triplet is preceded by a section-subscript that is a subscript.

    The : in second place is a subscript triplet, yet 1 in first place is a subscript.