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+i3*dxに格納されているアドレスにの変位を減算しeて を取得し(j+1)*dx+iます。同様に、取得2*dxするアドレスに追加します。しかし、SSE 組み込み関数を使用してこの戦略を実装する方法を知りません。dj-2

助けてください。Intel 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

(たとえば) の値はであり、そこから抜け出すことはできないため、可能な再配置によって、としてラベル付けした変数からこれらを取得することは絶対にできません。dedV[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 ( ) になりました。行内のデータの各オフセット バージョンを少なくとも 2 回計算しています。おそらく、ループを数回アンロールして、すべての余分な作業を避けることができます。

ヒント: なぜ AVX を使わないのですか? _mm256_permute_ps (および必要に応じて _mm256_permute2f128_ps) を使用してシャッフルし、対応するロード命令を使用します。2 倍の幅の SIMD レジスタがあり、ほとんどの AVX 命令は SSE 命令と同じように最新の CPU でも 1 サイクルしかかからないため、ほぼ 2 倍高速になります。

于 2013-01-27T07:12:10.000 に答える