使用SSE内在函数的大小为100 * 100的矩阵乘法

时间:2017-12-06 20:05:33

标签: c sse matrix-multiplication intrinsics

    int MAX_DIM = 100;
    float a[MAX_DIM][MAX_DIM]__attribute__   ((aligned(16)));
    float b[MAX_DIM][MAX_DIM]__attribute__   ((aligned(16)));
    float d[MAX_DIM][MAX_DIM]__attribute__   ((aligned(16)));
    /*
     * I fill these arrays with some values
     */

for(int i=0;i<MAX_DIM;i+=1){

      for(int j=0;j<MAX_DIM;j+=4){

        for(int k=0;k<MAX_DIM;k+=4){

          __m128 result = _mm_load_ps(&d[i][j]);

          __m128 a_line  = _mm_load_ps(&a[i][k]);

          __m128 b_line0 = _mm_load_ps(&b[k][j+0]);

          __m128 b_line1 = _mm_loadu_ps(&b[k][j+1]);

          __m128 b_line2 = _mm_loadu_ps(&b[k][j+2]);

          __m128 b_line3 = _mm_loadu_ps(&b[k][j+3]);

         result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(a_line, a_line, 0x00), b_line0));
         result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(a_line, a_line, 0x55), b_line1));
         result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(a_line, a_line, 0xaa), b_line2));
         result = _mm_add_ps(result, _mm_mul_ps(_mm_shuffle_ps(a_line, a_line, 0xff), b_line3));
         _mm_store_ps(&d[i][j],result);
        }
      }
    }

我使用SSE进行矩阵乘法的上述代码。代码以流的形式运行我从行中取4个元素乘以b中的4个元素,然后移动到b中a和next 4个元素的行中接下来的4个元素

我收到错误Segmentation fault (core dumped)我真的不知道为什么

我在ubuntu 16.04.5上使用gcc 5.4.0

编辑: 分段错误由_mm_loadu_ps解决 逻辑也有问题如果有人帮助我找到它,我会很高兴

1 个答案:

答案 0 :(得分:3)

  

分段错误由_mm_loadu_ps解决。逻辑也有问题......

您正在b[k][j+0..7]上加载4个重叠窗口。 (这就是你需要loadu)的原因。

也许您打算加载b[k][j+0]+4+8+12?如果是这样,您应该将b与64对齐,这样所有四个加载都来自同一个缓存行(性能)。跨步访问并不是很好,但是使用你接触的每个缓存行的所有64个字节比在标量代码中没有阻塞的行主要与列主要完全错误要好得多。

  

我从a行中取出4个元素,将b

列中的4个元素乘以

我不确定您的文字说明是否描述了您的代码。

除非您已经转置b,否则您无法在SIMD加载的情况下从同一列加载多个值,因为它们在内存中不是连续的。

C多维数组是&#34;行主要&#34;:最后一个索引是移动到下一个更高内存地址时变化最快的索引。你认为_mm_loadu_ps(&b[k][j+1])会给你b[k+0..3][j+1]吗?如果是这样,这是SSE matrix-matrix multiplication的副本(问题是使用32位整数,而不是32位浮点数,但布局问题相同。请参阅有关工作循环结构的信息。)

要对此进行调试,请将一个简单的值模式放入b[]。像

#include <stdalign.>

alignas(64) float b[MAX_DIM][MAX_DIM] = {
    0000, 0001, 0002, 0003, 0004, ...,
    0100, 0101, 0102, ...,
    0200, 0201, 0202, ...,
 };

 // i.e. for (...) b[i][j] = 100 * i + j;

然后当您在调试器中单步执行代码时,您可以看到向量中最终会出现哪些值。

对于您的a[][]值,可以使用90000.0 + 100 * i + j,因此,如果您正在查看寄存器(而不是C变量),您仍然可以判断哪些值为a,哪些值为b

相关: