fortranparameter-passingintel-fortranfortran-coarrays

Passing a coarray subarray to a function gives a wrong part of the array


I'm attempting to understand how to pass a slice of a multidimensional co-array to a function. I would like to use a function like this:

    function get_int_vec(vec_int_2get, rank) result(ret_val)
      implicit none
      integer,  dimension(:), codimension[*], intent(in) :: vec_int_2get
      integer, intent(in) :: rank
      integer, allocatable, dimension(:) :: ret_val 

      ret_val = vec_int_2get(:)[rank]

    end function ! get_int_vec

It works fine to get an entire array. But when passing a slice of a coarray, like:

    vec_getA(:) = get_int_vec(matrix_A(n, :), rank)

where matrix_A is declared as

    integer, dimension(:, :), codimension[:],  allocatable :: matrix_A

and properly allocated, I always get the first column of matrix_A instead of the n-th.

The gfortran passing conventions say:

" with -fcoarray=lib [...] the token and the offset belonging to nonallocatable coarrays dummy arguments are passed as hidden argument along the character length hidden arguments. The token is an opaque pointer identifying the coarray and the offset is a passed-by-value integer of kind C_PTRDIFF_T, denoting the byte offset between the base address of the coarray and the passed scalar or first element of the passed array."

So I was expecting the function to work fine also with matrix slices, since the offset from the beginning of the matrix should be passed along to the function.

There is something am I doing wrong?

If can be of some interest: I am compiling with Intel Parallel Studio XE 2018 cluster edition, and not the OpenCoarrays version of coarrays.


Solution

  • This seems to be a bug in Intel ifort 2018. The syntax of your code appears to conform with Fortran 2008 standard (here). The same code compiled with OpenCoarrays and GFortran yields the expected results. Here is a (not so minimal but) working implementation of your question:

    module coarrayFunc
        implicit none
    contains
        function get_int_vec(vec_int_2get, rank) result(ret_val)
            implicit none
            integer,  dimension(:), codimension[*], intent(in) :: vec_int_2get
            integer, intent(in) :: rank
            integer :: ret_val(3)
            !integer :: ret_val(size(vec_int_2get)) ! using this results in internal compiler error when compiled with ifort.
            !integer, allocatable :: ret_val(:) ! both ifort and OpenCoarrays (GFortran) compile with this declaration, however both ifort give wrong results.
            ret_val = vec_int_2get(:)[rank]
        end function ! get_int_vec
    end module coarrayFunc
    
    program testNoncontiguousCoarray
        use coarrayFunc
        implicit none
        integer, allocatable    :: matrix_A(:,:)[:], dummy(:)
        integer                 :: rank, n, i, j, image
        integer, parameter      :: ilower = 1, iupper = 5
        integer, parameter      :: jlower = 1, jupper = 3
    
        allocate( matrix_A(ilower:iupper,jlower:jupper)[*] )
    
        do i = ilower, iupper
            do j = jlower, jupper
                matrix_A(i,j) = this_image()*100 + i*10 + j
            end do
        end do
    
        ! print matrix_A on each image
        sync all
        if (this_image()==1) then
            do image = 1, num_images()
                write(*,"(*(g0))") "matrix_A on image ", image, ":"
                do i = ilower, iupper
                    write(*,"(*(g8.1))") matrix_A(i,:)[image]
                end do
                write(*,"(*(g0))")
            end do
            sync images(*)
        else
            sync images(1)
        end if
        sync all
    
        n = iupper
        rank = this_image()
        !rank = num_images()
    
        sync all
        if (this_image()==1) then
            write(*,"(*(g0))")
            write(*,"(*(g0))") "On all images: "
            write(*,"(*(g0))") "n = ", n
            write(*,"(*(g0))")
        end if
        sync all
    
        if (this_image()==1) then
            write(*,"(*(g0,' '))") "On Image ", this_image(), ": matrix_A( n =", n, ", : )[",rank,"] = ", matrix_A(n,:)[rank]
            dummy = get_int_vec(matrix_A(n,:), rank)
            write(*,"(*(g0,' '))") "On Image ", this_image(), ": get_int_vec( matrix_A( n =", n, ", : ), rank =", rank, ") = " &
                                   , dummy
        else
            sync images (this_image()-1)
            write(*,"(*(g0,' '))") "On Image ", this_image(), ": matrix_A( n =", n, ", : )[",rank,"] = ", matrix_A(n,:)[rank]
            dummy = get_int_vec(matrix_A(n,:), rank)
            write(*,"(*(g0,' '))") "On Image ", this_image(), ": get_int_vec( matrix_A( n =", n, ", : ), rank =", rank, ") = " &
                                   , dummy
        end if
        call sleep(1)
        if (this_image()<num_images()) sync images (this_image()+1)
    
    end program testNoncontiguousCoarray
    

    Compiling and running this code with OpenCoarrays yields:

    matrix_A on image 1:
        111     112     113
        121     122     123
        131     132     133
        141     142     143
        151     152     153
    
    matrix_A on image 2:
        211     212     213
        221     222     223
        231     232     233
        241     242     243
        251     252     253
    
    matrix_A on image 3:
        311     312     313
        321     322     323
        331     332     333
        341     342     343
        351     352     353
    
    matrix_A on image 4:
        411     412     413
        421     422     423
        431     432     433
        441     442     443
        451     452     453
    
    
    On all images: 
    n = 5
    
    On Image  1 : matrix_A( n = 5 , : )[ 1 ] =  151 152 153 
    On Image  1 : get_int_vec( matrix_A( n = 5 , : ), rank = 1 ) =  151 152 153 
    On Image  2 : matrix_A( n = 5 , : )[ 2 ] =  251 252 253 
    On Image  2 : get_int_vec( matrix_A( n = 5 , : ), rank = 2 ) =  251 252 253 
    On Image  3 : matrix_A( n = 5 , : )[ 3 ] =  351 352 353 
    On Image  3 : get_int_vec( matrix_A( n = 5 , : ), rank = 3 ) =  351 352 353 
    On Image  4 : matrix_A( n = 5 , : )[ 4 ] =  451 452 453 
    On Image  4 : get_int_vec( matrix_A( n = 5 , : ), rank = 4 ) =  451 452 453
    

    which outputs the result one would expect to get. Note that I have tweaked your original function so that the function's result would be an automatic array instead of allocatable (This appears to be yet another bug in OpenCoarrays, that is, an allocatable output return wrong results). Running the same code using ifort 2018 Windows would reproduce the error that you observe in your own implementation:

    >set FOR_COARRAY_NUM_IMAGES=4
    
    >ifort /Qcoarray=shared testNoncontiguousCoarray.f90 -o run.exe
    Intel(R) Visual Fortran Intel(R) 64 Compiler for applications running on Intel(R) 64, Version 18.0.2.185 Build 20180210
    Copyright (C) 1985-2018 Intel Corporation.  All rights reserved.
    
    Microsoft (R) Incremental Linker Version 14.13.26129.0
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    -out:run.exe
    -subsystem:console
    testNoncontiguousCoarray.obj
    
    >run.exe
    matrix_A on image 1:
         111     112     113
         121     122     123
         131     132     133
         141     142     143
         151     152     153
    
    matrix_A on image 2:
         211     212     213
         221     222     223
         231     232     233
         241     242     243
         251     252     253
    
    matrix_A on image 3:
         311     312     313
         321     322     323
         331     332     333
         341     342     343
         351     352     353
    
    matrix_A on image 4:
         411     412     413
         421     422     423
         431     432     433
         441     442     443
         451     452     453
    
    
    On all images:
    n = 5
    
    On Image  1 : matrix_A( n = 5 , : )[ 1 ] =  151 152 153
    On Image  1 : get_int_vec( matrix_A( n = 5 , : ), rank = 1 ) =  111 112 113
    On Image  2 : matrix_A( n = 5 , : )[ 2 ] =  251 252 253
    On Image  2 : get_int_vec( matrix_A( n = 5 , : ), rank = 2 ) =  211 212 213
    On Image  3 : matrix_A( n = 5 , : )[ 3 ] =  351 352 353
    On Image  3 : get_int_vec( matrix_A( n = 5 , : ), rank = 3 ) =  311 312 313
    On Image  4 : matrix_A( n = 5 , : )[ 4 ] =  451 452 453
    On Image  4 : get_int_vec( matrix_A( n = 5 , : ), rank = 4 ) =  411 412 413
    

    As mentioned in the comments to your question, consider writing a minimal working example of code that reproduces the error you get, and submit a ticket to Intel's ifort compiler team, for a potential resolution.