OpenCL通过引用传递不同的地址空间

OpenCL通过引用传递不同的地址空间,opencl,pass-by-reference,Opencl,Pass By Reference,短篇故事: 我有一个输出变量的传递引用函数 void acum( float2 dW, float4 dFE, float2 *W, float4 *FE ) 如果满足某些条件,则假定增量变量*W,*FE,乘以dW,dFE。 我想将此函数设置为通用-输出变量可以是本地变量,也可以是全局变量 acum( dW, dFE, &W , &FE ); // __local acum acum( W, FE, &Wout[idOut], &FEout[idOut]

短篇故事:

我有一个输出变量的传递引用函数

void acum( float2 dW, float4 dFE, float2 *W, float4 *FE )
如果满足某些条件,则假定增量变量*W,*FE,乘以dW,dFE。 我想将此函数设置为通用-输出变量可以是本地变量,也可以是全局变量

acum( dW, dFE, &W , &FE  );   // __local acum
acum( W, FE, &Wout[idOut], &FEout[idOut] );  // __global acum
当我试图编译它时,我得到了一个错误

error: illegal implicit conversion between two pointers with different address spaces
有没有可能以某种方式做到这一点???我在想我是否可以用宏代替函数(但我不太熟悉C语言中的宏)

另一种可能性可能是:

  • 使用返回结构{Wnew,FEnew}的函数
  • 或者(float8)(Wnew,FEnew,0,0),但我不喜欢它,因为它使代码更加混乱
  • 当然,我也不想只是到处复制“acum”的主体(比如手动内联它:)
  • backbound(无需阅读):

    我正在尝试使用OpenCL编程一些热力学采样。因为统计权重W=exp(-E/kT)很容易在低温下溢出浮点(2^64),所以我创建了一个组合数据类型W=float2(W_数字,W_指数),并定义了函数来处理这些数字“acum”

    我尽量减少全局内存操作的数量,所以我让work_项通过Vsurf而不是FEout,因为我希望Vsurf中只有很少的点具有相当大的统计权重,所以每个workitem只调用FEout的累积几次。而在FEout上迭代则需要sizeof(FEout)*sizeof(Vsurf)内存操作。 完整的代码在这里(欢迎任何关于如何使其更有效的建议):

    //====函数::FF_vdW-莱纳德·琼斯·范德瓦尔斯力场
    浮动4 FF_vdW(浮动3 R){
    常数浮点C6=1.0;
    常量浮点C12=1.0;
    浮动ir2=1.0/点(R,R);
    浮动ir6=ir2*ir2*ir2;
    浮动ir12=ir6*ir6;
    浮点数E6=C6*ir6;
    浮点数E12=C12*ir12;
    申报表(4)(
    (6*E6-12*E12)*ir2*R
    ,E12-E6
    );}
    //====函数::FF_弹簧-谐波力场
    浮动4 FF_弹簧(浮动3 R){
    常数float3k=(float3)(1.0,1.0,1.0);
    float3f=k*R;
    申报表(4)(F),
    0.5*点(F,R)
    );}
    //====函数::EtoW-计算统计权重
    浮动2 EtoW(浮动EkT){
    浮动Wexp=地板(EkT);
    返回(浮动2)(经验(EkT-Wexp)
    ,Wexp
    ); }
    //====程序:addExpInplace—使用统计权重dW计算F,E
    无效acum(浮动2 dW、浮动4 dFE、浮动2*W、浮动4*FE)
    {
    float dExp=dW.y-(*W.y;//log(dW)-log(W)
    如果(dExp>-22){//e^22=2^32,则单浮点数=2^+64
    浮点数fac=exp(dExp);
    if(dExp logWcut
    float kT//应取样的最大能量
    ) {
    int id=get_global_id(0);//在潜在网格点上循环
    int idx=id/nV.x;
    int3 iV=(int3)(idx/nV.y)
    ,idx%nV.y
    ,id%nV.x);
    浮点数V=Vsurf[id];
    浮动3 RXe=dV*iV;
    
    如果(VOK,下面是OpenCL手册页中发生的事情:

    如果对象的类型由地址空间名称限定,则该对象在指定的地址名称中分配;否则,该对象在通用地址空间中分配

    程序中函数的参数或函数的局部变量的通用地址空间名为_私有。所有函数参数都应在_私有地址空间中

    因此,acum(…)函数参数位于_私有地址空间中

    因此,编译器的说法是正确的

    acum(..&Wout[idOut]、&FEout[idOut])

    在全局addrress空间中使用&Wout和&FEout调用,而函数args必须位于专用地址空间中

    解决方案是在全局和私有之间进行转换

    创建两个私有临时变量以接收结果

    用这些变量调用acum(…)

    调用acum(..)后,将临时私有值指定给全局值

    代码看起来有点混乱


    请记住,在GPU上有许多地址空间,您不能通过强制转换在它们之间神奇地跳转。您必须通过赋值在地址空间之间显式移动数据。

    您还可以将全局限定符添加到必要的accum(…)函数args。但是您将得到两个函数,一个带全局函数,一个不带。并且您需要不同的名称,因为在ISOC99中没有函数名重载。
    // ===== function :: FF_vdW  - Lenard-Jones Van Der Waals forcefield
    float4 FF_vdW ( float3 R ){
     const float C6    = 1.0;
     const float C12   = 1.0;
     float ir2  = 1.0/ dot( R, R );
     float ir6  = ir2*ir2*ir2;
     float ir12 = ir6*ir6;
     float E6   = C6*ir6;
     float E12  = C12*ir12;
     return (float4)(     
                    ( 6*E6  -  12*E12 ) * ir2    *  R 
                    ,   E12 -     E6
    );}
    
    // ===== function :: FF_spring  - harmonic forcefield
    float4 FF_spring( float3 R){
     const float3 k = (float3)(  1.0, 1.0, 1.0 );
     float3 F = k*R;
     return (float4)(  F,
                       0.5*dot(F,R)
    );}
    
    // ===== function :: EtoW    -   compute statistical weight
    float2 EtoW( float EkT ){
        float Wexp = floor( EkT);
        return (float2)(  exp(EkT - Wexp)
                       ,   Wexp
    ); }
    
    // ===== procedure : addExpInplace    -- acumulate F,E with statistical weight dW
    void acum( float2 dW, float4 dFE, float2 *W, float4 *FE   )
    {
                float dExp = dW.y - (*W).y; // log(dW)-log(W)
                if(dExp>-22){               // e^22 = 2^32 ,    single_float = 2^+64
                   float fac = exp(dExp); 
                   if (dExp<0){             // log(dW)<log(W)
                     dW.x *= fac;
                     (*FE)    += dFE*dW.x;
                     (*W ).x  +=     dW.x;
                   }else{                   // log(dW)>log(W)
                     (*FE)     = dFE  + fac*(*FE); 
                     (*W ).x   = dW.x + fac*(*W).x;
                     (*W ).y   = dW.y;
                   }
                }
    }
    
    // ===== __kernel :: sampler
    __kernel void sampler( 
    __global float  * Vsurf, // in  : surface potential (including vdW)  // may be faster to precomputed endpoints positions like float8
    __global float4 * FEout, // out : Fx,Fy,Fy, E
    __global float2 * Wout,  // out : W_digits, W_exponent
    int3   nV    ,
    float3 dV    ,
    int3   nOut     ,
    int3   iOut0    ,        // shift of Fout in respect to Vsurf
    int3   nCopy    ,        // number of copies of 
    int3   nSample  ,        // dimension of sampling in each dimension around R0   +nSample,-nSample
    float3 RXe0     ,        // postion Xe relative to Tip
    float  EcutSurf ,        
    float  EcutTip  ,        
    float  logWcut  ,        // accumulate only when  log(W) > logWcut
    float  kT                // maximal energy which should be sampled
    ) {
    
        int  id  = get_global_id(0);  // loop over potential grid points
        int  idx = id/nV.x; 
        int3 iV  =  (int3)( idx/nV.y
                          , idx%nV.y
                          , id %nV.x  );
        float V = Vsurf[id];
        float3 RXe = dV*iV;
    
    if (V<EcutSurf){
    // loop over tip position
    for (int iz=0;iz<nOut.z;iz++ ){
    for (int iy=0;iy<nOut.y;iy++ ){
    for (int ix=0;ix<nOut.x;ix++ ){ 
    
        int3   iTip = (int3)( iz, iy, ix );
        float3 Rtip = dV*iTip;
        float4 FE = 0;
        float2 W  = 0;
        // loop over images of potential
        for (int ix=0;ix<nCopy.x;ix++ ){
        for (int iy=0;iy<nCopy.y;iy++ ){
            float3 dR = RXe - Rtip;
            float4 dFE    = FF_vdW( dR );
                   dFE   += FF_spring( dR - RXe0 );
                   dFE.w += V;
    
            if( dFE.w < EcutTip  ){
                float2 dW = EtoW( - FE.w / kT );
                acum( dW, dFE, &W , &FE  );   // __local acum
            }
        } 
        }
    
        if( W.y > logWcut  ){ // accumulate force
            int  idOut = iOut0.x + iOut0.y*nOut.x + iOut0.z*nOut.x*nOut.y;
            acum( W, FE, &Wout[idOut], &FEout[idOut] );  // __global acum
        }
    
    }}}}
    
    }