You say that program speed is important, so old-style Fortran will give you the best:
- allocate a 1D array of size
MAX
- pass is to a subroutine as well as
NX
,NY
,and NZ
. This will avoid the pointer
indirection that will give you a loss of performance (unlike C, the Fortran standard
assumes that subroutine array arguments don't overlap, see this post).
For example:
program noptrtest
implicit none
integer, parameter :: MAX = 50 ! I know this number on compile time.
integer :: NX,NY ! I will find this numbers on run time.
real :: a(MAX) ! Static Array
read(*,*) NX, NY ! I get NX, NY (NX*NY == MAX)
if (NX*NY /= MAX) then
stop 'NX*NY /= MAX'
endif
call run(a,NX,NY)
end program noptrtest
subroutine run(b,NX,NY)
integer :: NX,NY
real :: b(NX,NY)
integer :: i,j
do j=1,NY
do i=1,NX
! use b(i,j) here
enddo
enddo
end
If performance really matters here are some other useful tricks:
- Tell your compiler to align the arrays on a 32-byte boundary (with ifort, use the
!DIR$ ATTRIBUTES ALIGN : 32
directive
- Dimension physically your 2D array such that the size of leading dimension is a multiple of 32-bytes. For real*4, you need a multiple of 8 elements.
- Tell the compiler that each column is properly aligned using the
!DIR$ VECTOR ALIGNED
directive
For example:
program noptrtest
implicit none
integer, parameter :: real_kind = 4
integer, parameter :: MAX = 50 ! I know this number on compile time.
integer, parameter :: MAXDIM = MAX*(32/real_kind) ! Max possible dimension required
integer :: NX,NY, NX_MOD ! I will find this numbers on run time.
real(real_kind) :: a(MAXDIM) ! Static Array
!DIR$ ATTRIBUTES ALIGN : 32 :: a
read(*,*) NX, NY ! I get NX, NY (NX*NY == MAX)
if (NX*NY /= MAX) then
stop 'NX*NY /= MAX'
endif
if (mod(NX,real_kind) == 0) then
NX_MOD = NX
else
NX_MOD = ((NX/real_kind)+1)*real_kind
endif
call run(a,NX_MOD,NX,NY)
end program noptrtest
subroutine run(b,NX_MOD,NX,NY)
integer :: NX_MOD,NX,NY
real :: b(NX_MOD,NY)
integer :: i,j
do j=1,NY
!DIR$ VECTOR ALIGNED
do i=1,NX
! use b(i,j) here
enddo
enddo
end
Edit
This old-style Fortran trick avoids pointer aliasing.
References on pointer aliasing: