0

http://blogs.msdn.com/b/xiangfan/archive/2009/04/28/optimize-your-code-matrix-multiplication.aspxを参照してください。

template<>
void SeqMatrixMult4(int size, float** m1, float** m2, float** result)
{
    Transpose(size, m2);
    for (int i = 0; i < size; i++) {
        for (int j = 0; j < size; j++) {
            __m128 c = _mm_setzero_ps();

            for (int k = 0; k < size; k += 4) {
                c = _mm_add_ps(c, _mm_mul_ps(_mm_load_ps(&m1[i][k]), _mm_load_ps(&m2[j][k])));
            }
            c = _mm_hadd_ps(c, c);
            c = _mm_hadd_ps(c, c);
            _mm_store_ss(&result[i][j], c);
        }
    }
    Transpose(size, m2);
}

_mm_hadd_ps(c, c)最も内側のforループの後に2つあるのはなぜですか?私の理解を確認するために:このコードはm1から4つのfloatをロードし、m2から別の4つのfloatをロードし、それらを乗算して4つのfloat(__m128)を生成します。次に、それらを合計しますc(この時点では、まだ4つのフロートですか?)。次に、forループの後、haddこの結果は2回ですか?それは何をしますか?


少し書き直したコードでは、間違った結果が表示されます

long long start, end;
__m128 v1, v2, vMul, vRes;
vRes = _mm_setzero_ps();

start = wall_clock_time();
transpose_matrix(m2);
for (int i = 0; i < SIZE; i++) {
    for (int j = 0; j < SIZE; j++) {
        float tmp = 0;
        for (int k = 0; k < SIZE; k+=4) {
            v1 = _mm_load_ps(&m1[i][k]);
            v2 = _mm_load_ps(&m2[j][k]);
            vMul = _mm_mul_ps(v1, v2);

            vRes = _mm_add_ps(vRes, vMul);
        }
        vRes = _mm_hadd_ps(vRes, vRes);
        _mm_store_ss(&result[i][j], vRes);
    }
}
end = wall_clock_time();
fprintf(stderr, "Optimized Matrix multiplication took %1.2f seconds\n", ((float)(end - start))/1000000000);

// reverse the transposition
transpose_matrix(m2);
4

1 に答える 1

4

haddpsベクトル内の4つの要素すべてを合計するわけではありません。完全な水平方向の合計を取得するには、 2つのhaddps命令が必要です。

ベクトルの要素に番号を付ける{c0,c1,c2,c3}と、最初にhaddpsが生成され{c0+c1, c2+c3, c0+c1, c2+c3}ます。2番目はを生成し{c0+c1+c2+c3, <same thing in the other lanes>}ます。

于 2012-10-03T23:47:48.680 に答える