6

SSE組み込み関数を初めて使用していますが、16バイトのメモリアライメントを確認した後でも、セグメンテーション違反が発生しています。この投稿は私の以前の質問の拡張です:

16バイトのメモリ整列データを割り当てる方法

これが私の配列を宣言した方法です:

  float *V = (float*) memalign(16,dx*sizeof(float));

私がこれをやろうとすると:

  __m128 v_i = _mm_load_ps(&V[i]); //It works

しかし、私がこれを行うとき:

  __m128 u1 = _mm_load_ps(&V[(i-1)]); //There is a segmentation fault

しかし、私がそうするなら:

  __m128 u1 = _mm_loadu_ps(&V[(i-1)]); //It works again

ただし、使用を排除し、使用のみ_mm_loadu_psで機能させたいと考えています。_mm_load_ps

私はインテル®ICCコンパイラーを使用しています。

この問題を解決するにはどうすればよいですか?

アップデート:

次のコードで両方の操作を使用します。

  void FDTD_base (float *V, float *U, int dx, float c0, float c1, float c2, float c3,     float c4)
    {
       int i, j, k;
                    for (i = 4; i < dx-4; i++)
                    {

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

       }

SSEバージョン:

         for (i=4; i < dx-4; i+=4)
        {
            v_i = _mm_load_ps(&V[i]);
            __m128 center = _mm_mul_ps(v_i,c0_i);

            __m128 u1 = _mm_loadu_ps(&V[(i-1)]);
            u2 = _mm_loadu_ps(&V[(i+1)]);

            u3 = _mm_loadu_ps(&V[(i-2)]);
            u4 = _mm_loadu_ps(&V[(i+2)]);

            u5 = _mm_loadu_ps(&V[(i-3)]);
            u6 = _mm_loadu_ps(&V[(i+3)]);

            u7 = _mm_load_ps(&V[(i-4)]);
            u8 = _mm_load_ps(&V[(i+4)]);

            __m128 tmp1 = _mm_add_ps(u1,u2);
            __m128 tmp2 = _mm_add_ps(u3,u4);
            __m128 tmp3 = _mm_add_ps(u5,u6);
            __m128 tmp4 = _mm_add_ps(u7,u8);

            __m128 tmp5 = _mm_mul_ps(tmp1,c1_i);
            __m128 tmp6 = _mm_mul_ps(tmp2,c2_i);
            __m128 tmp7 = _mm_mul_ps(tmp3,c3_i);
            __m128 tmp8 = _mm_mul_ps(tmp4,c4_i);

            __m128 tmp9 = _mm_add_ps(tmp5,tmp6);
            __m128 tmp10 = _mm_add_ps(tmp7,tmp8);

            __m128 tmp11 = _mm_add_ps(tmp9,tmp10);
            __m128 tmp12 = _mm_add_ps(center,tmp11);

            _mm_store_ps(&U[i], tmp12);
    }

のみを使用してこれを行うより効率的な方法はあり_mm_load_ps()ますか?

4

1 に答える 1

11

sizeof(float)は4なので、の4つおきのエントリのみがV適切に配置されます。_mm_load_ps一度に4つのフロートをロードすることを忘れないでください。引数、つまり最初のfloatへのポインタは、16バイトに揃える必要があります。

あなたの例iでは4の倍数であると仮定しています。そうでない_mm_load_ps(&V[i])と失敗します。

アップデート

これは、整列されたロードとシャッフルを使用して上記のスライディングウィンドウの例を実装することを提案する方法です。

__m128 v_im1;
__m128 v_i = _mm_load_ps( &V[0] );
__m128 v_ip1 = _mm_load_ps( &V[4] );

for ( i = 4 ; i < dx ; i += 4 ) {

    /* Get the three vectors in this 'frame'. */
    v_im1 = v_i; v_i = v_ip1; v_ip1 = _mm_load_ps( &V[i+4] );

    /* Get the u1..u8 from the example code. */
    __m128 u3 = _mm_shuffle_ps( v_im1 , v_i , 3 + (4<<2) + (0<<4) + (1<<6) );
    __m128 u4 = _mm_shuffle_ps( v_i , v_ip1 , 3 + (4<<2) + (0<<4) + (1<<6) );

    __m128 u1 = _mm_shuffle_ps( u3 , v_i , 1 + (2<<2) + (1<<4) + (2<<6) );
    __m128 u2 = _mm_shuffle_ps( v_i , u4 , 1 + (2<<2) + (1<<4) + (2<<6) );

    __m128 u5 = _mm_shuffle_ps( v_im1 , u3 , 1 + (2<<2) + (1<<4) + (2<<6) );
    __m128 u6 = _mm_shuffle_ps( u4 , v_ip1 , 1 + (2<<2) + (1<<4) + (2<<6) );

    __m128 u7 = v_im1;
    __m128 u8 = v_ip1;

    /* Do your computation and store. */
    ...

    }

_mm_shuffle_ps各引数から2つの値しか取得できないため、これは少し注意が必要です。そのため、最初に作成u3u4て、重複が異なる他の値に再利用する必要があります。

また、値u1、、、u3およびは、、および前の反復でu5復元できることにも注意してください。u2u4u6

最後に、上記のコードを検証していないことに注意してください。のドキュメントを読み、_mm_shuffle_ps3番目の引数であるセレクターがそれぞれの場合に正しいことを確認してください。

于 2012-06-18T15:29:34.020 に答える