Compiler construction 传递包含不同编译器(PGI和Intel)之间可分配数组的fortran派生类型

Compiler construction 传递包含不同编译器(PGI和Intel)之间可分配数组的fortran派生类型,compiler-construction,fortran,intel,pgi,Compiler Construction,Fortran,Intel,Pgi,我们有一个项目,它发展了Nvidia GPU和英特尔至强Phi。主机代码和GPU代码用Fortran编写,并由pgfortran编译。为了将部分工作转移到Phi,我们必须创建一个由ifort编译的共享库(静态链接无法工作),并从代码的pgfortran部分调用共享子例程。通过这样做,我们可以将阵列从pgfortran部分的代码卸载到可以与Xeon Phi通信的intel fortran共享库 现在,我尝试将一个派生类型(包含可分配数组)从代码的pgfortran部分传递到ifort共享库。看来有

我们有一个项目,它发展了Nvidia GPU和英特尔至强Phi。主机代码和GPU代码用Fortran编写,并由pgfortran编译。为了将部分工作转移到Phi,我们必须创建一个由ifort编译的共享库(静态链接无法工作),并从代码的pgfortran部分调用共享子例程。通过这样做,我们可以将阵列从pgfortran部分的代码卸载到可以与Xeon Phi通信的intel fortran共享库

现在,我尝试将一个派生类型(包含可分配数组)从代码的pgfortran部分传递到ifort共享库。看来有些问题

下面是一个简单的示例(此处没有Xeon Phi卸载指令):

caller.f90:

program caller                                                                           

type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell                                                                            

integer :: n,i,j

type(cell) :: cl(2)                                                                      
 n=10                                                                                    
do i=1,2                                                                                 
allocate(cl(i)%a(n))                                                                     
allocate(cl(i)%b(n))                                                                     
allocate(cl(i)%c(n))                                                                     
end do                                                                                   


do j=1, 2                                                                                
do i=1, n                                                                                
cl(j)%a(i)=10*j+i                                                                        
cl(j)%b(i)=10*i+j                                                                        
end do                                                                                   
end do                                                                                   


call offload(cl(1))                                                                      
print *, cl(1)%c  
end program caller
program caller
use iso_c_binding

type, bind(C) :: cell_C                                                                               
integer :: id                                                                            
integer :: na, nb, nc
type(c_ptr)  :: a,b,c                                                                                                                             
end type cell_C

type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell                                                                            

integer :: n,i,j

type(cell),target :: cl(2)
type(cell_c) :: cl_c
 n=10                                                                                    
do i=1,2                                                                                 
allocate(cl(i)%a(n))                                                                     
allocate(cl(i)%b(n))                                                                     
allocate(cl(i)%c(n))                                                                     
end do                                                                                   

do j=1, 2                                                                                
do i=1, n                                                                                
cl(j)%a(i)=10*j+i                                                                        
cl(j)%b(i)=10*i+j                                                                        
end do                                                                                   
end do                                                                                   

cl_c%a = c_loc(cl(1)%a)
cl_c%b = c_loc(cl(1)%b)
cl_c%c = c_loc(cl(1)%c)
cl_c%na =  size(cl(1)%a)
cl_c%nb =  size(cl(1)%b)
cl_c%nc =  size(cl(1)%c)
cl_c%id =  cl(1)%id

call offload(cl_c)                                                                      
print *, cl(1)%c  
end program caller
调用.f90:

subroutine  offload(cl)                                                                  
type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell

type(cell) :: cl                                                                         
integer :: n

print *, cl%a(1:10)
print *, cl%b(1:10)   
end subroutine offload    
subroutine  offload(cl_c)                                                                  
use iso_c_binding

type, bind(C) :: cell_C                                                                               
integer :: id                                                                            
integer :: na, nb, nc
type(c_ptr)  :: a,b,c                                                                                                                             
end type cell_C

type cell                                                                               
integer :: id
real, pointer :: a(:)                                                                
real, pointer :: b(:)                                                                
real, pointer :: c(:)                                                                
end type cell

type(cell) :: cl
type(cell_C) :: cl_C
integer :: n

cl%id = cl_C%id
call c_f_pointer(cl_C%a, cl%a, [cl_c%na])
call c_f_pointer(cl_C%b, cl%b, [cl_c%nb])
call c_f_pointer(cl_C%c, cl%c, [cl_c%nc])

print *, cl%a(1:10)
print *, cl%b(1:10)   
end subroutine offload  
生成文件:

run: caller.o libcalled.so
           pgfortran  -L. caller.o -lcalled  -o $@
caller.o: caller.f90
           pgfortran  -c caller.f90
libcalled.so: called.f90
           ifort  -shared -fPIC $^ -o $@
注意这里的“
cl%a(1:10)
”,没有“
(1:10)
”将不会打印任何内容

这段代码最终打印出了
cl(1)%a
中的元素,然后在下一行中遇到了分段错误,我试图打印出数组
cl(1)%b

如果我将“
cl%a(1:10)
”更改为“cl%a(1:100)”,并删除“
print*,cl%b(1:10)
”。它将给出以下结果:

我们可以发现b数组中的元素在那里,但我无法通过“
cl%b(1:10)
”获取它们

我知道这可能是由不同编译器的不同派生类型结构造成的。但是我真的想要一种方法,通过它我们可以在编译器之间传递这种派生类型。有什么解决办法吗


谢谢大家!

编译器的ABI可能不同。您不应该直接传递结构,而是在子例程中构建它们并使用指针,这些指针应该作为
类型(c_ptr)
或假定大小数组传递(但是可以进行复制!)

Fortran 2003中与C的互操作性不仅仅意味着与C交互,还意味着与C交互的任何其他编译器。它可以是不同的Fortran编译器

请注意,在更多位置声明同一类型并将其用作同一类型是违反Fortran规则的,除非该类型是
sequence
bind(C)
。这是您的程序不符合标准的另一个原因

调用.f90:

subroutine  offload(cl)                                                                  
type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell

type(cell) :: cl                                                                         
integer :: n

print *, cl%a(1:10)
print *, cl%b(1:10)   
end subroutine offload    
subroutine  offload(cl_c)                                                                  
use iso_c_binding

type, bind(C) :: cell_C                                                                               
integer :: id                                                                            
integer :: na, nb, nc
type(c_ptr)  :: a,b,c                                                                                                                             
end type cell_C

type cell                                                                               
integer :: id
real, pointer :: a(:)                                                                
real, pointer :: b(:)                                                                
real, pointer :: c(:)                                                                
end type cell

type(cell) :: cl
type(cell_C) :: cl_C
integer :: n

cl%id = cl_C%id
call c_f_pointer(cl_C%a, cl%a, [cl_c%na])
call c_f_pointer(cl_C%b, cl%b, [cl_c%nb])
call c_f_pointer(cl_C%c, cl%c, [cl_c%nc])

print *, cl%a(1:10)
print *, cl%b(1:10)   
end subroutine offload  
caller.f90:

program caller                                                                           

type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell                                                                            

integer :: n,i,j

type(cell) :: cl(2)                                                                      
 n=10                                                                                    
do i=1,2                                                                                 
allocate(cl(i)%a(n))                                                                     
allocate(cl(i)%b(n))                                                                     
allocate(cl(i)%c(n))                                                                     
end do                                                                                   


do j=1, 2                                                                                
do i=1, n                                                                                
cl(j)%a(i)=10*j+i                                                                        
cl(j)%b(i)=10*i+j                                                                        
end do                                                                                   
end do                                                                                   


call offload(cl(1))                                                                      
print *, cl(1)%c  
end program caller
program caller
use iso_c_binding

type, bind(C) :: cell_C                                                                               
integer :: id                                                                            
integer :: na, nb, nc
type(c_ptr)  :: a,b,c                                                                                                                             
end type cell_C

type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell                                                                            

integer :: n,i,j

type(cell),target :: cl(2)
type(cell_c) :: cl_c
 n=10                                                                                    
do i=1,2                                                                                 
allocate(cl(i)%a(n))                                                                     
allocate(cl(i)%b(n))                                                                     
allocate(cl(i)%c(n))                                                                     
end do                                                                                   

do j=1, 2                                                                                
do i=1, n                                                                                
cl(j)%a(i)=10*j+i                                                                        
cl(j)%b(i)=10*i+j                                                                        
end do                                                                                   
end do                                                                                   

cl_c%a = c_loc(cl(1)%a)
cl_c%b = c_loc(cl(1)%b)
cl_c%c = c_loc(cl(1)%c)
cl_c%na =  size(cl(1)%a)
cl_c%nb =  size(cl(1)%b)
cl_c%nc =  size(cl(1)%c)
cl_c%id =  cl(1)%id

call offload(cl_c)                                                                      
print *, cl(1)%c  
end program caller
使用gfortran和ifort:

>gfortran  called.f90 -c -o called.o
>ifort  caller.f90 -c -o caller.o
>ifort -o a.out called.o caller.o -lgfortran
>./a.out
11.0000000       12.0000000       13.0000000       14.0000000       15.0000000       16.0000000       17.0000000       18.0000000       19.0000000       20.0000000    
   11.0000000       21.0000000       31.0000000       41.0000000       51.0000000       61.0000000       71.0000000       81.0000000       91.0000000       101.000000    
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
这里不需要动态库

对于100%的理论可移植性,可以使用
c_int
c_float
,。。。格式可能更好,等等,但你明白了


您还可以重载
单元格
单元格_C
之间的赋值,以简化转换。

编译器的ABI可能不同。您不应该直接传递结构,而是在子例程中构建它们并使用指针,这些指针应该作为
类型(c_ptr)
或假定大小数组传递(但是可以进行复制!)

Fortran 2003中与C的互操作性不仅仅意味着与C交互,还意味着与C交互的任何其他编译器。它可以是不同的Fortran编译器

请注意,在更多位置声明同一类型并将其用作同一类型是违反Fortran规则的,除非该类型是
sequence
bind(C)
。这是您的程序不符合标准的另一个原因

调用.f90:

subroutine  offload(cl)                                                                  
type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell

type(cell) :: cl                                                                         
integer :: n

print *, cl%a(1:10)
print *, cl%b(1:10)   
end subroutine offload    
subroutine  offload(cl_c)                                                                  
use iso_c_binding

type, bind(C) :: cell_C                                                                               
integer :: id                                                                            
integer :: na, nb, nc
type(c_ptr)  :: a,b,c                                                                                                                             
end type cell_C

type cell                                                                               
integer :: id
real, pointer :: a(:)                                                                
real, pointer :: b(:)                                                                
real, pointer :: c(:)                                                                
end type cell

type(cell) :: cl
type(cell_C) :: cl_C
integer :: n

cl%id = cl_C%id
call c_f_pointer(cl_C%a, cl%a, [cl_c%na])
call c_f_pointer(cl_C%b, cl%b, [cl_c%nb])
call c_f_pointer(cl_C%c, cl%c, [cl_c%nc])

print *, cl%a(1:10)
print *, cl%b(1:10)   
end subroutine offload  
caller.f90:

program caller                                                                           

type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell                                                                            

integer :: n,i,j

type(cell) :: cl(2)                                                                      
 n=10                                                                                    
do i=1,2                                                                                 
allocate(cl(i)%a(n))                                                                     
allocate(cl(i)%b(n))                                                                     
allocate(cl(i)%c(n))                                                                     
end do                                                                                   


do j=1, 2                                                                                
do i=1, n                                                                                
cl(j)%a(i)=10*j+i                                                                        
cl(j)%b(i)=10*i+j                                                                        
end do                                                                                   
end do                                                                                   


call offload(cl(1))                                                                      
print *, cl(1)%c  
end program caller
program caller
use iso_c_binding

type, bind(C) :: cell_C                                                                               
integer :: id                                                                            
integer :: na, nb, nc
type(c_ptr)  :: a,b,c                                                                                                                             
end type cell_C

type cell                                                                                
integer :: id                                                                            
real, allocatable :: a(:)                                                                
real, allocatable :: b(:)                                                                
real, allocatable :: c(:)                                                                
end type cell                                                                            

integer :: n,i,j

type(cell),target :: cl(2)
type(cell_c) :: cl_c
 n=10                                                                                    
do i=1,2                                                                                 
allocate(cl(i)%a(n))                                                                     
allocate(cl(i)%b(n))                                                                     
allocate(cl(i)%c(n))                                                                     
end do                                                                                   

do j=1, 2                                                                                
do i=1, n                                                                                
cl(j)%a(i)=10*j+i                                                                        
cl(j)%b(i)=10*i+j                                                                        
end do                                                                                   
end do                                                                                   

cl_c%a = c_loc(cl(1)%a)
cl_c%b = c_loc(cl(1)%b)
cl_c%c = c_loc(cl(1)%c)
cl_c%na =  size(cl(1)%a)
cl_c%nb =  size(cl(1)%b)
cl_c%nc =  size(cl(1)%c)
cl_c%id =  cl(1)%id

call offload(cl_c)                                                                      
print *, cl(1)%c  
end program caller
使用gfortran和ifort:

>gfortran  called.f90 -c -o called.o
>ifort  caller.f90 -c -o caller.o
>ifort -o a.out called.o caller.o -lgfortran
>./a.out
11.0000000       12.0000000       13.0000000       14.0000000       15.0000000       16.0000000       17.0000000       18.0000000       19.0000000       20.0000000    
   11.0000000       21.0000000       31.0000000       41.0000000       51.0000000       61.0000000       71.0000000       81.0000000       91.0000000       101.000000    
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00  0.0000000E+00
这里不需要动态库

对于100%的理论可移植性,可以使用
c_int
c_float
,。。。格式可能更好,等等,但你明白了


您还可以重载
单元格
单元格_C
之间的赋值,以简化转换。

called.f90中单元格中的a(:)、b(:)、C(:)是否可以分配数组?我试过了,它会给出一个双重自由或腐败错误。我有点需要其中一个是可分配的数组,以便分配给特定的卸载。不,它们不能。可分配的只能是特定编译器分配的内存中的某些内容。如果它是由另一个编译器分配的,它必须由指针指向。然而,我不明白你是如何用可分配项编译它的,如果你使用我的答案中的建议,这应该是不可能的。我不明白你为什么需要它。如果你真的需要它们,你只需要从指针数组复制那里的值。因为我尝试使用一个Xeon Phi卸载指令,它可以将主机上的一个数组卸载到Xeon Phi上具有不同名称的另一个数组。例如,如果主机上的阵列A和B的大小都为m,并且我们有一个大小为2m的可分配阵列C,那么我可以将A卸载到Phi上C的前半部分,将B卸载到Phi上C的后半部分。但是,如果我们定义一个指向C的指针,并将其用作卸载指令的一部分,那么就会出现问题。这就是我不需要指针的原因。我不需要C数组中的内容,我只需要C数组的名称,Intel映射主机和设备数组的名称。但是数组指针会导致卸载指令出现问题。called.f90中单元格中的a(:)、b(:)、c(:)是否可以分配数组?我试过了,它会给出一个双重自由或腐败错误。我有点需要其中一个是可分配的数组,以便分配给特定的卸载。不,它们不能。可分配的只能是特定编译器分配的内存中的某些内容。如果它是由另一个编译器分配的,它必须由指针指向。然而,我不明白你是如何用可分配项编译它的,如果你使用我的答案中的建议,这应该是不可能的。我不明白你为什么需要它。如果你真的需要它们,你只需要从指针数组复制那里的值