如何使用C中的SSE内部函数计算矢量点积

我试图将两个向量相乘,其中一个向量的每个元素乘以另一个向量的相同索引中的元素。 然后,我想总结得到的向量的所有元素以获得一个数字。 例如,对于向量{1,2,3,4}和{5,6,7,8},计算结果如下:

1 * 5 + 2 * 6 + 3 * 7 + 4 * 8

基本上,我正在采用两个向量的点积。 我知道有一个SSE命令来执行此操作,但该命令没有与之关联的内部函数。 此时,我不想在我的C代码中编写内联汇编,所以我只想使用内部函数。 这似乎是一个常见的计算,所以我很惊讶自己在Google上找不到答案。

注意:我正在针对特定的微架构进行优化,该架构最多支持SSE 4.2。

谢谢你的帮助。

GCC(至少版本4.3)包括带有SSE4.1级内在函数的 ,包括单精度和双精度点积:

 _mm_dp_ps (__m128 __X, __m128 __Y, const int __M); _mm_dp_pd (__m128d __X, __m128d __Y, const int __M); 

作为旧处理器的后备,您可以使用此算法创建向量ab的点积:

 r1 = _mm_mul_ps(a, b); r2 = _mm_hadd_ps(r1, r1); r3 = _mm_hadd_ps(r2, r2); _mm_store_ss(&result, r3); 

英特尔在这里发表了一篇文章,涉及点产品实现。

我写了这个并用gcc -O3 -S -ftree-vectorize -ftree-vectorizer-verbose=2 sse.c编译它

 void f(int * __restrict__ a, int * __restrict__ b, int * __restrict__ c, int * __restrict__ d, int * __restrict__ e, int * __restrict__ f, int * __restrict__ g, int * __restrict__ h, int * __restrict__ o) { int i; for (i = 0; i < 8; ++i) o[i] = a[i]*e[i] + b[i]*f[i] + c[i]*g[i] + d[i]*h[i]; } 

GCC 4.3.0自动矢量化它:

 sse.c:5: note: LOOP VECTORIZED. sse.c:2: note: vectorized 1 loops in function. 

但是,如果我使用具有足够迭代的循环,它只会这样做 - 否则详细输出将阐明矢量化无利可图或循环太小。 如果没有__restrict__关键字,它必须生成单独的非矢量化版本,以处理输出o可能指向其中一个输入的情况。

我会粘贴说明作为示例,但由于部分向量化展开了循环,因此它不是非常易读。

我会说最快的SSE方法是:

 static inline float CalcDotProductSse(__m128 x, __m128 y) { __m128 mulRes, shufReg, sumsReg; mulRes = _mm_mul_ps(x, y); // Calculates the sum of SSE Register - https://stackoverflow.com/a/35270026/195787 shufReg = _mm_movehdup_ps(mulRes); // Broadcast elements 3,1 to 2,0 sumsReg = _mm_add_ps(mulRes, shufReg); shufReg = _mm_movehl_ps(shufReg, sumsReg); // High Half -> Low Half sumsReg = _mm_add_ss(sumsReg, shufReg); return _mm_cvtss_f32(sumsReg); // Result in the lower part of the SSE Register } 

我跟着 – 最快的方式做x86上的水平浮动矢量和 。