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

Explicit-shape dummy array are always contiguous?

AlbP
Beginner
347 Views

Hello,

 

I am trying to understand whether a dummy array is contiguous or not.

More specifically, my need is to understand whether I can be sure that an array received by a Fortran routine can given as a buffer to an interoperable C function making sure that the data are contiguous in memory.

Currently, I do have explicit-shape dummy arrays and what I am experiencing with ifort (and with gfortran as well) is that non-contiguous actual arrays are copied into a temporary storage when the actual argument is not contiguous.

In fact, one may potentially send array strides to a Fortran routine, that could be not contiguous and then could cause problem when sent to a C function via a C pointer of the buffer and a total size.

I am wondering if this is required by the standard, or if it is just the current implementation in ifort.

 

Let us consider this reduced example

module myarray
use iso_c_binding
use iso_fortran_env
implicit none

contains

function intloc(cptr)
implicit none
integer(kind=int64) :: intloc
type(c_ptr), intent(in) :: cptr

intloc = transfer(cptr, 1_int64)
end function intloc

subroutine dumvect(myvect)
implicit none

#if METHOD==1
! assumed-shape
integer, dimension(:), intent(in), target :: myvect
#elif METHOD==2
! assumed-share + contiguous
integer, dimension(:), intent(in), target, contiguous :: myvect
#elif METHOD==3
! explicit-shape
integer, dimension(5), intent(in), target :: myvect
#elif METHOD==4
! assumed-size
integer, dimension(*), intent(in), target :: myvect
#endif
integer :: i

write(*,*) "--> Inside routine as dummy array"
#if METHOD==4
write(*,*) is_contiguous(myvect), intloc(c_loc(myvect)), myvect(1:5)
do i=1,5
#else
write(*,*) is_contiguous(myvect), intloc(c_loc(myvect)), myvect
do i=1,size(myvect)
#endif
  write(*,*) intloc(c_loc(myvect(i)))
enddo
end subroutine dumvect

end module myarray


program tstarrtyp
use iso_c_binding
use myarray
implicit none
integer :: i
integer, dimension(:), allocatable, target :: vect
integer, dimension(:), pointer :: subvect

allocate(vect(10))

vect = [ (i, i=1,10) ]
subvect => vect(1:10:2)

write(*,*) "--> Original array"
write(*,*) intloc(c_loc(vect)), vect
do i=1,10
  write(*,*) intloc(c_loc(vect(i)))
enddo

write(*,*) '--> Stride array'
write(*,*) intloc(c_loc(subvect)), subvect
do i=1,5
  write(*,*) intloc(c_loc(subvect(i)))
enddo

call dumvect(subvect)

deallocate(vect)

end program tstarrtyp

 

Here are the results obtained with ifort 19.1.2:

METHOD Contiguous dummy (dumvect routine)
1 False
2 True
3 True
4 True

 

I tried the "-check arg_temp_created" as suggested by Steve, which indeed shows me when the copy is created.

The results obtained for #1 and #2 are pretty obvious, although I am not sure whether those of cases #3 and #4 are just compiler-dependent.

 

Thank you for your help!

0 Kudos
4 Replies
mecej4
Black Belt
319 Views

I do not know a simple answer to your question.

Some aspects of contiguity are processor-dependent, and some can be controlled or set using the CONTIGUOUS attribute, which is discussed in section 5.3.7 of the F2008 standard. Arguments passed to C routines in conformity with the ISO-C interoperability features may have additional properties that the programmer may depend on or apply control to. 

JohnNichols
Valued Contributor II
300 Views
program Console1

    implicit none

    INTEGER, CONTIGUOUS, POINTER :: ap(:)
    INTEGER, TARGET :: targ(10)
    INTEGER, POINTER :: ip(:)
    LOGICAL :: contig

    ! Invalid because ap is contiguous. A severe error is issued at compile time.
    ap => targ(1:10:2)
    ip => targ(1:10:2)
    ! contig has a value of .FALSE.
    contig = IS_CONTIGUOUS(ip)

    write(*,*) contig

    ! contig has a value of .TRUE.
    ALLOCATE(ip(10))
    contig = IS_CONTIGUOUS(ip)
    write(*,*) contig

    end program Console1

 

I am having trouble understanding why you would want ap to be contiguous, and why have two pointers that point to the same array elements with a stride of 2.  

it would make the program awful to understand later on, it is like the vestiges of a horrendous common block.  

 

JohnNichols
Valued Contributor II
298 Views
AlbP
Beginner
229 Views

By looking at Metcalf's book (last 2018 edition "incorporating Fortran 2018") §19.5 page 372 (inside the interoperability with C chapter), we can read

"Implementations usually receive explicit-shape and assumed-size arrays in contiguous storage [...] They will need to make a copy of any array argument that is not stored contiguously, unless the dummy argument is assumed-shape"

This seems confirming what I am observing. It is just the "usually" that keeps me thinking, but practically speaking I cannot image any implementation working with explicit-shape or assumed-size arrays without dealing with contiguous memory.

Reply