我必须从Fortran调用C函数,但我想在矢量化循环中执行此操作。我正在使用Linux上的Intel 16.0.3编译器。
所以选项是:我可以尝试将函数内联或者我可以使用SIMD函数(我想使用OpenMP SIMD,我希望它是可移植的,我已经使用了OpenMP)。
如果我从Fortran调用Fortran,它可以双向工作。对于传递参数,我使用线性/ ref子句将引用传递给值向量而不是引用向量,这似乎有效。但在C中,线性/ ref子句无法识别。
我可以得到名义矢量化的功能,但它插入了收集和散射,性能并不比标量好(至少对于我的小测试函数)。
如果我将linear(ref(r,s))
放在Fortran接口块中,我会收到消息
不得在伪参数上使用UVAL或REF修饰符 VALUE属性。
我可以使用从Fortran传递值并返回值作为函数返回的技巧来获得性能。这会产生一个矢量化函数,性能也很好,但遗憾的是我的实函数需要返回多个值。
如果我尝试内联C函数,它就行不通。 opt报告告诉我,无法内联呼叫站点。即使使用标量函数也是如此。我根本无法将C函数内联到Fortran中。我正在使用ipo尝试这样做。我想知道内联问题是否可能是Fortran传递指针指针?但随后代码给出了正确的答案,似乎它在某种程度上是可以接受的。
测试代码(传递指针)本质上是......
Fortran来电者
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;
}
答案 0 :(得分:2)
LINEAR(REF())
很新,所以人们只能希望使用OMP和CONTIGUOUS的LINEAR可以让你高兴。
消息:
不得在具有VALUE属性的伪参数上使用UVAL或REF修饰符。"
表示它在堆栈上正在执行值。我以为C阵列在heap
?但也许你需要一个-heap
开关?
<强> C-侧:强>
我建议您向linear
#pragma
#pragma omp declare simd linear(r,s)
您是否考虑过使用#pragma vector aligned
?还#pragma ivdep
?
我假设(* r)是一个引用(在堆中)
<强> F90边强>
我建议你替换:
real(8), allocatable :: r(:), s(:)
与
!$DIR ATTRIBUTES ALIGN:64 :: R, S
REAL(KIND=8), DIMENSION(:), ALLOCATABLE, CONTIGUOUS :: R, S
这里唯一真正的变化是64位对齐和连续。 也可以使用switch -align array64byte
如果ierror
不是数组,那么你想要一个吗?或者您是否需要在ierror
上使用第一个/最后一个私有或减少条款?我可能会使用减少。
!$OMP SIMD
然后转到:
!$OMP DO SIMD REDUCTION(ierror)
但是当你提到你需要多个值时,你可能需要分配ierror
吗?
我感兴趣的是接口如何知道它的返回值为零。好像你必须在界面的某个地方有INTEGER FUNCTION。
链接 - 编译方:
如果C生成F90-
MODULE,那么USE将允许它在C代码中看到足够深的内联或其他帮助。因此,您可能需要编译器/链接上的-IPO
以允许F90了解它可以对C被调用者做什么。
答案 1 :(得分:0)
睡了之后,我想知道你是否应该有一个空白,并在你的接口规范上使用子程序?
另一种选择似乎是: INTEGER FUNCTION simd_c_func然后在FORTRAN侧的SIMD中使用REDUCTION。
但是这些都没有解决你得到的实际编译器消息。 而且我看到你已经使用过-IPO了。
您可以尝试替换: LINEAR(REF(R,S)) 同 LINEAR(REF(R),REF(S))