は、私がこれまでに得たものである:SSE行列 - 行列乗算
#define N 1000
void matmulSSE(int mat1[N][N], int mat2[N][N], int result[N][N]) {
int i, j, k;
__m128i vA, vB, vR;
for(i = 0; i < N; ++i) {
for(j = 0; j < N; ++j) {
vR = _mm_setzero_si128();
for(k = 0; k < N; k += 4) {
//result[i][j] += mat1[i][k] * mat2[k][j];
vA = _mm_loadu_si128((__m128i*)&mat1[i][k]);
vB = _mm_loadu_si128((__m128i*)&mat2[k][j]); //how well does the k += 4 work here? Should it be unrolled?
vR = _mm_add_epi32(vR, _mm_mul_epi32(vA, vB));
}
vR = _mm_hadd_epi32(vR, vR);
vR = _mm_hadd_epi32(vR, vR);
result[i][j] += _mm_extract_epi32(vR, 0);
}
}
}
私はそれを作るように見えることはできません正しい結果を出してください。何か不足していますか? そしてdosent検索は非常に役立つように見える - すべての結果は唯一の4x4行列をやって、マット-VECまたは非常に読みやすく、理解するのは難しいことではないthatsのいくつかの特別な魔法のどちらかです...
更新: Woho!私はついにそれを理解した。私のロジックのエラー(ヘルプPeter Cordesのおかげです)に加えて、_mm_mul_epi32()の問題もありました。私は思ったとおりに動作しませんでした。代わりに_mm_mullo_epi32()を使用していたはずです!
私はこれが最も効果的なコードではないことを知っていますが、最初に正しく動作するようになっています。今は最適化を進めることができます。
void matmulSSE(int mat1[N][N], int mat2[N][N], int result[N][N]) {
int i, j, k;
__m128i vA, vB, vR, vSum;
for(i = 0; i < N; ++i) {
for(j = 0; j < N; ++j) {
vR = _mm_setzero_si128();
for(k = 0; k < N; k += 4) {
//result[i][j] += mat1[i][k] * mat2[k][j];
vA = _mm_loadu_si128((__m128i*)&mat1[i][k]);
vB = _mm_insert_epi32(vB, mat2[k][j], 0);
vB = _mm_insert_epi32(vB, mat2[k + 1][j], 1);
vB = _mm_insert_epi32(vB, mat2[k + 2][j], 2);
vB = _mm_insert_epi32(vB, mat2[k + 3][j], 3);
vR = _mm_mullo_epi32(vA, vB);
vR = _mm_hadd_epi32(vR, vR);
vR = _mm_hadd_epi32(vR, vR);
result[i][j] += _mm_extract_epi32(vR, 0);
//DEBUG
//printf("vA: %d, %d, %d, %d\n", vA.m128i_i32[0], vA.m128i_i32[1], vA.m128i_i32[2], vA.m128i_i32[3]);
//printf("vB: %d, %d, %d, %d\n", vB.m128i_i32[0], vB.m128i_i32[1], vB.m128i_i32[2], vB.m128i_i32[3]);
//printf("vR: %d, %d, %d, %d\n", vR.m128i_i32[0], vR.m128i_i32[1], vR.m128i_i32[2], vR.m128i_i32[3]);
//printf("\n");
}
}
}
}
アップデート2:がi-K-Jループ順バージョンにピーターズ例を変換します。 vRに余分な負荷が必要で、ストア内でインナーループに移動する必要がありますが、設定されたvAをループの上に移動できます。速くなった。
void matmulSSE_2(int mat1[N][N], int mat2[N][N], int result[N][N]) {
int i, j, k;
__m128i vA, vB, vR;
for(i = 0; i < N; ++i) {
for(k = 0; k < N; ++k) {
vA = _mm_set1_epi32(mat1[i][k]);
for(j = 0; j < N; j += 4) {
//result[i][j] += mat1[i][k] * mat2[k][j];
vB = _mm_loadu_si128((__m128i*)&mat2[k][j]);
vR = _mm_loadu_si128((__m128i*)&result[i][j]);
vR = _mm_add_epi32(vR, _mm_mullo_epi32(vA, vB));
_mm_storeu_si128((__m128i*)&result[i][j], vR);
//DEBUG
//printf("vA: %d, %d, %d, %d\n", vA.m128i_i32[0], vA.m128i_i32[1], vA.m128i_i32[2], vA.m128i_i32[3]);
//printf("vB: %d, %d, %d, %d\n", vB.m128i_i32[0], vB.m128i_i32[1], vB.m128i_i32[2], vB.m128i_i32[3]);
//printf("vR: %d, %d, %d, %d\n", vR.m128i_i32[0], vR.m128i_i32[1], vR.m128i_i32[2], vR.m128i_i32[3]);
//printf("\n");
}
}
}
}
問題は何ですか? –
@RushyPanchal私は正しい結果を得ていません。申し訳ありませんが、私は自分の投稿に指定しておくべきです... – Erlisch
呼び出し元が 'result []'をゼロにしていますか?そうでない場合は、まずそれを行う必要があります!また、最も内側のループの内側で水平の合計を行うことは恐ろしいことに注意してください。同じ最内側のループの中で 'result [i] [j]'のためにすべての計算を行うなら '+ ='ではなく 'result = hsum(vR)'を実行してください。ここで、hsumは非MSVCに移植可能な水平和関数です(問題がある場合)、コンパイラがあなたが書いたもののためにおそらく生成するものよりも少なくなります。 http://stackoverflow.com/questions/6996764/fastest-way-to-do-horizontal-float-vector-sum-on-x86を参照してください。私の答えは整数hsumsです。 –