c - 向量内积的几何意义 - 向量叉乘求导



如何在C中使用SSE内部函数来计算向量点积 (3)

我试图将两个向量相乘在一起,其中一个向量的每个元素都与另一个向量的相同索引中的元素相乘。 然后,我想对所得到的矢量的所有元素进行求和以获得一个数字。 例如,对于矢量{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级别内在函数的<smmintrin.h> ,包括单精度和双精度点积:

_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://.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上的水平浮点矢量和





simd