У меня возникают проблемы, делая умножение матрицы на матрицу с SSE в С.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);
}
}
}
Я не могу это сделать дать правильные результаты. Я что-то упускаю? и поиск доцент, кажется, очень помогает - каждый результат либо только делает матрицы 4x4, мат-VEC или какая-то особая магия то не очень читаемый и трудно понять ...
Update: Woho! Я наконец-то понял. Помимо ошибок в моей логике (спасибо за помощь Питера Кордеса), также возникла проблема с _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: конвертированы пример Peters к I-к-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. –