1

我正在尝试仅使用对齐、加载和存储来矢量化 2D 模板。为此,我想基本上使用_mm_load_ps_mm_shuffle_ps获得所需的地址。

我的代码标量版本是:

    void FDTD_base (float *V, float *U, int dx, int dy, float c0, float c1, float c2, float c3, float c4)
    {
    int i, j, k;

            for (j = 4; j < dy-4; j++)
            {
                    for (i = 4; i < dx-4; i++)
                    {

                            U[j*dx+i] = (c0 * (V[j*dx+i]) //center
                                    + c1 * (V[j*dx+(i-1)] + V[(j-1)*dx+i] + V[j*dx+(i+1)] + V[(j+1)*dx+i] )
                                    + c2 * (V[j*dx+(i-2)] + V[(j-2)*dx+i] + V[j*dx+(i+2)] + V[(j+2)*dx+i] )
                                    + c3 * (V[j*dx+(i-3)] + V[(j-3)*dx+i] + V[j*dx+(i+3)] + V[(j+3)*dx+i] )
                                    + c4 * (V[j*dx+(i-4)] + V[(j-4)*dx+i] + V[j*dx+(i+4)] + V[(j+4)*dx+i] ));

                    }
            }

      }

到目前为止,我的向量查看代码版本:

     for (j = 4; j < dy-4; j++)
    {
            for (i = 4; i < dx-4; i+=4)
            {
                    __m128 b = _mm_load_ps(&V[j*dx+i]);
                    center = _mm_mul_ps(b,c0_i);
                    a = _mm_load_ps(&V[j*dx+(i-4)]);
                    c = _mm_load_ps(&V[j*dx+(i+4)]);

                    d = _mm_load_ps(&V[(j-4)*dx+i]);
                    e = _mm_load_ps(&V[(j+4)*dx+i]);

                    u_i2 = _mm_shuffle_ps(a,b,_MM_SHUFFLE(1,0,3,2));//i-2
                    u_i6 = _mm_shuffle_ps(b,c,_MM_SHUFFLE(1,0,3,2));//i+2

                    u_i1 = _mm_shuffle_ps(u_i2,b,_MM_SHUFFLE(2,1,2,1));//i-1
                    u_i5 = _mm_shuffle_ps(b,u_i6,_MM_SHUFFLE(2,1,2,1));//i+1

                    u_i3 = _mm_shuffle_ps(a,u_i2,_MM_SHUFFLE(2,1,2,1));//i-3
                    u_i7 = _mm_shuffle_ps(u_i6,c,_MM_SHUFFLE(2,1,2,1));//i+3

                    u_i4 = a; //i-4
                    u_i8 = c; //i+4

有人可以帮我获得 j-1,j+1 .....j-4,j+4 的位置吗?

这不起作用:

                    u_j2 = _mm_shuffle_ps(d,b,_MM_SHUFFLE(1,0,3,2));//j-2 (this is incorrect)
                    u_j6 = _mm_shuffle_ps(b,e,_MM_SHUFFLE(1,0,3,2));//j+2

                    u_j1 = _mm_shuffle_ps(u_j2,b,_MM_SHUFFLE(2,1,2,1));//j-1
                    u_j5 = _mm_shuffle_ps(b,u_j6,_MM_SHUFFLE(2,1,2,1));//j+1

                    u_j3 = _mm_shuffle_ps(d,u_j2,_MM_SHUFFLE(2,1,2,1));//j-3
                    u_j7 = _mm_shuffle_ps(u_j6,e,_MM_SHUFFLE(2,1,2,1));//j+3

                    u_j4 = d; //j-4 (this is fine)
                    u_j8 = e; //j+4

我只需要帮助来确定如何获得(j-1)*dx+i(j+1)*dx+1......(j-4)*dx+i并且(j+4)*dx+i不使用未对齐的负载。

作为一种潜在的解决方案,我想在3*dx存储的地址中添加位移d以获得(j-1)*dx+i. 3*dx并减去存储的地址的位移e以获得(j+1)*dx+i。类似地添加2*dx到地址d以获得j-2等等。但我不知道使用 SSE 内在函数来实施此策略。

请帮忙。我正在使用英特尔 icc 编译器。

4

1 回答 1

0

“谁能帮我获得 j-1,j+1 .....j-4,j+4 的位置。” - 这些不需要洗牌;它们已经与您的 SIMD 通道对齐。

u_j2 = _mm_load_ps(&V[(j-2)*dx+i]); 
u_j6 = _mm_load_ps(&V[(j+2)*dx+i]); 
u_j1 = _mm_load_ps(&V[(j-1)*dx+i]); 
u_j5 = _mm_load_ps(&V[(j+1)*dx+i]); 
// and so forth

绝对不能从您标记为的变量中获得这些,d并且e通过任何可能的重新排列,因为d(例如)中的值是V[j-4, i], V[j-4, i+1], V[j-4, i+2], V[j-4, i+3],并且您无法V[j-2, i]摆脱它。

提示:考虑 SIMD 通道;这清楚地表明您需要水平而不是垂直重新排列。

提示:考虑当内部循环计数器递增 ( i+=4) 时会发生什么。V[j, i+1..i+5]上一个循环中的 u_i5 ( ) 现在是V[j, i-3..i+1]当前循环中的 u_i3 ( )。您正在计算行中数据的每个偏移版本至少两次。您可能可以多次展开循环并避免做所有额外的工作。

提示:为什么不使用 AVX?使用 _mm256_permute_ps (和 _mm256_permute2f128_ps 如果需要)洗牌,以及相应的加载指令。它几乎快两倍,因为你有两倍宽的 SIMD 寄存器,并且大多数 AVX 指令在现代 CPU 上仍然只需要一个周期,与 SSE 指令相同。

于 2013-01-27T07:12:10.000 回答