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)|
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!
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.
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.
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.