C 内在函数、SSE2 点积和 gcc -O3 生成的程序集

标签 c assembly sse

我需要使用 SSE2 编写一个点积(没有 _mm_dp_ps 也没有 _mm_hadd_ps):

#include <xmmintrin.h>

inline __m128 sse_dot4(__m128 a, __m128 b)
{
    const __m128 mult = _mm_mul_ps(a, b);
    const __m128 shuf1 = _mm_shuffle_ps(mult, mult, _MM_SHUFFLE(0, 3, 2, 1));
    const __m128 shuf2 = _mm_shuffle_ps(mult,mult, _MM_SHUFFLE(1, 0, 3, 2));
    const __m128 shuf3 = _mm_shuffle_ps(mult,mult, _MM_SHUFFLE(2, 1, 0, 3));

    return _mm_add_ss(_mm_add_ss(_mm_add_ss(mult, shuf1), shuf2), shuf3);
}

但我用 gcc 4.9(实验)-O3 查看了生成的汇编器,我得到:

    mulps   %xmm1, %xmm0
    movaps  %xmm0, %xmm3         //These lines
    movaps  %xmm0, %xmm2         //have no use
    movaps  %xmm0, %xmm1         //isn't it ?
    shufps  $57, %xmm0, %xmm3
    shufps  $78, %xmm0, %xmm2
    shufps  $147, %xmm0, %xmm1
    addss   %xmm3, %xmm0
    addss   %xmm2, %xmm0
    addss   %xmm1, %xmm0
    ret

我想知道为什么 gcc 在 xmm1、2 和 3 中复制 xmm0... 这是我使用标志获得的代码:-march=native(看起来更好)

    vmulps  %xmm1, %xmm0, %xmm1
    vshufps $78, %xmm1, %xmm1, %xmm2
    vshufps $57, %xmm1, %xmm1, %xmm3
    vshufps $147, %xmm1, %xmm1, %xmm0
    vaddss  %xmm3, %xmm1, %xmm1
    vaddss  %xmm2, %xmm1, %xmm1
    vaddss  %xmm0, %xmm1, %xmm0
    ret

最佳答案

这是一个仅使用原始 SSE 指令的点积,它还会在每个元素之间混合结果:

inline __m128 sse_dot4(__m128 v0, __m128 v1)
{
    v0 = _mm_mul_ps(v0, v1);

    v1 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(2, 3, 0, 1));
    v0 = _mm_add_ps(v0, v1);
    v1 = _mm_shuffle_ps(v0, v0, _MM_SHUFFLE(0, 1, 2, 3));
    v0 = _mm_add_ps(v0, v1);

    return v0;
}

这是 5 条 SIMD 指令(而不是 7 条),但没有真正的机会来隐藏延迟。任何元素都将保存结果,例如,float f = _mm_cvtss_f32(sse_dot4(a, b);

haddps 指令有非常糟糕的延迟。使用 SSE3:

inline __m128 sse_dot4(__m128 v0, __m128 v1)
{
    v0 = _mm_mul_ps(v0, v1);

    v0 = _mm_hadd_ps(v0, v0);
    v0 = _mm_hadd_ps(v0, v0);

    return v0;
}

虽然它只有 3 个 SIMD 指令,但它可能更慢。如果您一次可以做多个点积,则可以在第一种情况下交错指令。 Shuffle 在最近的微架构上非常快。

关于C 内在函数、SSE2 点积和 gcc -O3 生成的程序集,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17000999/

相关文章:

c - 如何复制和分配数组数组?

c - 在 C 中索引数组会返回段错误

assembly - 将常量字节值移动到 %ebx 时出错

c - SSE 中浮点到 uchar 的转换问题

c++ - 在 Visual Studio 2015 中检测要与 C++ 宏一起使用的 SIMD 指令集

使用 eclipse 和 mingw 的控制台应用程序(不在 cms.exe 中启动应用程序)

c - 如何在 QNX Momentics 6.5 中使用不同的编译标准?

assembly - 每个函数名称后面的 @n ("at sign") 是什么?

c++ - 从 C++ 调用 putchar 地址

c++ - SSE 舍入精度