I have to call a C function from Fortran, but I want to do this in a vectorised loop. I am working with Intel 16.0.3 compilers on Linux.
So the options are: I can try and get the function to inline or I can use a SIMD function (I want to use OpenMP SIMD for this, I want it to be portable and I already use OpenMP).
If I call Fortran from Fortran it works both ways. For passing arguments I use the linear/ref clause to pass a reference to a vector of values rather than a vector of references and this seems to work efficiently. But in C the linear/ref clause is not recognised.
I can get the function to nominally vectorise but it is inserting gathers and scatters and performance is no better than scalar (at least for my small test function).
If I put linear(ref(r,s)) in the Fortran interface block I get the message
The UVAL or REF modifiers must not be used on a dummy argument with the VALUE attribute.
I can get the performance using the trick of passing by value from Fortran and returning a value as the function return. This produces a vectorised function, and performance is good, but unfortunately my real function needs to return more than one value.
If I try to inline the C function, it just won't work. The opt-report just tells me the callsite cannot be inlined. This is true even with a scalar function. I cannot get C functions to inline into Fortran at all. I am using ipo to try and do this. I have wondered if the inlining problem could be Fortran passing a pointer to a pointer? But then as the code gives the right answers it seems that it somehow acceptable.
The test code (passing pointers) is essentially...
Fortran caller
Use, intrinsic :: ISO_C_BINDING
….
real*8, allocatable :: r(:),s(:) .
….
interface
integer simd_c_func(r,s) bind(c, name="simd_c_func")
!$OMP DECLARE SIMD(simd_c_func)
import :: C_DOUBLE
real(kind=C_DOUBLE), intent(inout):: r,s
end interface
allocate....
!$OMP SIMD
do i=1,N
ierror=simd_c_func(r(i),s(i))
enddo
C callee
#pragma omp declare simd
int simd_c_func(double *r, double *s) {
(*r)+=(*s);
return 0;
}