将SIMD命令引入代码中的麻烦

时间:2011-07-31 17:57:36

标签: simd

我有一个基本的计算函数,我应用于数组中的每个项目。这个函数做的不仅仅是对两个向量求和。

我想使用SIMD命令并行处理数组中的多个项目。

我发现这些示例对我的情况来说太简单了(它们不包括函数调用): http://www.doc.ic.ac.uk/~nloriant/files/scfpsc-pc.pdf

我尝试使用数组表示法,如下所示: http://software.intel.com/sites/products/documentation/hpc/composerxe/en-us/cpp/mac/optaps/common/optaps_elem_functions.htm

但这并没有加速我的代码。我不明白我做错了什么,如果我需要更加类似汇编的SIMD风格,我该如何在那里引入函数调用......

如果有人可以帮助我,或者根据我的需要向我推荐一个好的来源,那我就非常有用。

谢谢!!!!


代码示例:

这是应用于数组中每个项目的基本功能:

float VarFlow::gauss_seidel_step(IplImage* u, int i, float h, float J11, float J12, float J13, float vi){

int x = i%u->width;
int y = i/u->width;

int start_y, end_y, start_x, end_x;
int N_num = 0;

start_y = y - 1;
end_y = y + 1;
start_x = x - 1;
end_x = x+1;         

float temp_u = 0;

// Sum top neighbor    
if(start_y > -1){              

    temp_u += *((float*)(u->imageData + start_y*u->widthStep) + x);

    N_num++;

}

// Sum bottom neighbor            
if(end_y < u->height){   

    temp_u += *((float*)(u->imageData + end_y*u->widthStep) + x);

    N_num++;

}

// Sum left neighbor
if(start_x > -1){              

    temp_u += *((float*)(u->imageData + y*u->widthStep) + start_x);

    N_num++;

}

// Sum right neighbor
if(end_x < u->width){              

    temp_u += *((float*)(u->imageData + y*u->widthStep) + end_x);

    N_num++;

}

temp_u = temp_u - (h*h/alpha)*(J12*vi + J13);
temp_u = temp_u / (N_num + (h*h/alpha)*J11);

return temp_u;

}

我想用__declspec(vector)声明它并像这样调用它:

    u_ptr[0:max_i:1] = gauss_seidel_step(imgU, vect[0:max_i:1], h, fxfx_ptr[0:max_i:1], fxfy_ptr[0:max_i:1], fxft_ptr[0:max_i:1], v_ptr[0:max_i:1]);
    v_ptr[0:max_i:1] = gauss_seidel_step(imgV, vect[0:max_i:1], h, fyfy_ptr[0:max_i:1], fxfy_ptr[0:max_i:1], fyft_ptr[0:max_i:1], u_ptr[0:max_i:1]);

而不是for循环。

我很乐意为此提供方向(可能是类似示例的链接),但不是完整解决方案。

谢谢!

1 个答案:

答案 0 :(得分:3)

SIMD和条件分支不能很好地混合。

将条件语句转换为布尔掩码和乘法。这会让你走向正确的路径来进行矢量化操作。

e.g。

if(end_x < u->width){                  
    temp_u += value;    
    N_num++;    
}

变为

ltmask = (end_x < u->width); // see _mm_cmplt_ps
temp_u += ltmask*value; // see _mm_add_ps, _mm_and_ps
N_num += ltmask; // use _mm_and_ps with a vector of 1.0f