c - 使用 SSE 向量指令加速矩阵-矩阵乘法
问题描述
我在使用 SSE 向量指令对一些 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 x int32 结果,而不是_mm_mul_epi32
2 x int64 结果。如果您不能使用 SSE4.1,请查看此处的答案以获取替代 SSE2 解决方案。
英特尔内在指南的完整描述:
_mm_mullo_epi32:将a和b中打包的32位整数相乘,产生中间64位整数,并将中间整数的低32位存储在dst中。
_mm_mul_epi32:将 a 和 b 中每个打包的 64 位元素的低 32 位整数相乘,并将带符号的 64 位结果存储在 dst 中。
推荐阅读
- r - 在 geom_sf 中填充连续颜色
- javascript - 使用 React refs 处理鼠标事件
- salesforce - 通过 aura:attribute 引用静态资源
- java - 未找到依赖项 'org.springframework.boot:spring-boot-starter-validation:2.5.1'
- firebase - 使用 List 列表创建 Document 时,Flutter App 崩溃
- javascript - Next.js Express 自定义服务器 { dev: true } 永远加载(空响应)但生产 { dev: false } 有效
- python - 重构多个 if / elif 语句,包括不等式
- reactjs - RTL - 测试 expect(onChange).toHaveBeenCalledWith({ name, value }) 不工作
- sql - SQL Server:获取日期+过去2个财政年度的数据
- android - ConstraintLayout 的 ViewStub 膨胀