c - 使用 SSE vector 指令加速矩阵-矩阵乘法

标签 c vector sse

我在使用 SSE vector 指令向量化一些 C 代码时遇到了一些麻烦。我必须胜利的代码是

#define N 1000
void matrix_mul(int mat1[N][N], int mat2[N][N], int result[N][N])
{
   int i, j, k;
   for (i = 0; i < N; ++i)
   {
      for (j = 0; j < N; ++j)
      {
         for (k = 0; k < N; ++k)
         {
              result[i][k] += mat1[i][j] * mat2[j][k];
         }
      }
   }
}

这是我到目前为止得到的:

void  matrix_mul_sse(int mat1[N][N], int mat2[N][N], int result[N][N])
{
   int i, j, k; int* l;
   __m128i v1, v2, v3;
   v3 = _mm_setzero_si128();
   for (i = 0; i < N; ++i)
   {
       for (j = 0; j < N; j += 4)
       {

           for (k = 0; k < N; k += 4)
           {

               v1 = _mm_set1_epi32(mat1[i][j]);
               v2 = _mm_loadu_si128((__m128i*)&mat2[j][k]);
               v3 = _mm_add_epi32(v3, _mm_mul_epi32(v1, v2));
               _mm_storeu_si128((__m128i*)&result[i][k], v3);
               v3 = _mm_setzero_si128();
           }
       }
   }
}

执行后我得到了错误的结果。我知道原因是从内存加载到 v2。我按行主要顺序遍历 mat1,所以我需要加载 mat2[0][0]、mat2[1][0]、mat2[2][0]、mat2[3][0]...但是什么实际上加载的是mat2[0][0], mat2[0][1], mat2[0][2], mat2[0][3]... 因为mat2已经按行主次序存储在内存中了。我试图解决这个问题,但没有任何改进。 谁能帮帮我。

最佳答案

下面修复了你的实现:

void  matrix_mul_sse(int mat1[N][N], int mat2[N][N], int result[N][N])
{
   int i, j, k;
   __m128i v1, v2, v3, v4; 
   for (i = 0; i < N; ++i)
   {
       for (j = 0; j < N; ++j) // 'j' must be incremented by 1
       {
           // read mat1 here because it does not use 'k' index
           v1 = _mm_set1_epi32(mat1[i][j]); 
           for (k = 0; k < N; k += 4)
           {   
               v2 = _mm_loadu_si128((const __m128i*)&mat2[j][k]);

               // read what's in the result array first as we will need to add it later to our calculations
               v3 = _mm_loadu_si128((const __m128i*)&result[i][k]);

               // use _mm_mullo_epi32 here instead _mm_mul_epi32 and add it to the previous result
               v4 = _mm_add_epi32(v3, _mm_mullo_epi32(v1, v2));

               // store the result
               _mm_storeu_si128((__m128i*)&result[i][k], v4);
           }
       }
   }
}

简而言之,_mm_mullo_epi32(需要 SSE4.1)产生 4 个 int32 结果,而 _mm_mul_epi32 产生 2 个 int64 结果。如果您不能使用 SSE4.1,请查看答案 here寻找替代的 SSE2 解决方案。

完整描述 Intel Intrinsic Guide :

_mm_mullo_epi32: Multiply the packed 32-bit integers in a and b, producing intermediate 64-bit integers, and store the low 32 bits of the intermediate integers in dst.

_mm_mul_epi32: Multiply the low 32-bit integers from each packed 64-bit element in a and b, and store the signed 64-bit results in dst.

关于c - 使用 SSE vector 指令加速矩阵-矩阵乘法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53064185/

相关文章:

vector - 将法向量旋转到轴平面上

algorithm - 在SSE/AVX中选择唯一/重复数据删除

optimization - SSE 是多余的还是不鼓励的?

c - matlab,我如何从多个文件夹中读取

c - 二叉搜索树插入在 C 中无法正常运行(可能是无知错误)

c - Pthread与C语言

c - fwrite 不写入整个缓冲区

C++ 显示具有 vector 的 map

c++ - 顺时针和逆时针旋转数组的有效方法

c - 在声明时初始化 union 数组