如何最大限度地减少开销加载到使用标量SIMD内在函数的simd寄存器中

时间:2018-01-02 05:28:37

标签: c++ simd intrinsics sse2

在godbolt.org上使用gcc 7.2我可以看到以下code在汇编程序中得到了最佳的翻译。我看到1个加载,1个加法和1个商店。

#include <immintrin.h>

__attribute__((alwaysinline)) double foo(double x, double y)
{
    return x+y;
}

void usefoo(double x, double *y, double *z)
{
    *z = foo(x, *y);
}

导致:

usefoo(double, double*, double*):
   addsd xmm0, QWORD PTR [rdi]
   movsd QWORD PTR [rsi], xmm0
   ret

但是,如果我尝试使用下面的code使用内在函数和模板来实现相同的功能,我可以看到添加了一些开销。特别是,教学的重点是什么:movq xmm0, xmm0

#include <immintrin.h>

__attribute__((alwaysinline)) double foo(double x, double y)
{
    return _mm_cvtsd_f64(_mm_add_sd(__m128d{x}, __m128d{y}));
}

void usefoo(double x, double *y, double *z)
{
    *z = foo(x, *y);
}

导致:

usefoo(double, double*, double*):
  movq xmm1, QWORD PTR [rdi]
  movq xmm0, xmm0
  addsd xmm0, xmm1
  movlpd QWORD PTR [rsi], xmm0
  ret

如何使用标量内在函数实现与编译器生成的代码等效的代码?

如果您想知道我为什么要这样做,请考虑将+替换为<=:如果我写x<y,编译器会将结果转换为bool,而内部会保留它作为双位掩码。因此,对于我的用例,编写x<y不是一种选择。但是,使用+非常简单,可以说明问题。

1 个答案:

答案 0 :(得分:3)

&#34;无关&#34; movq正在清除__m128d中的第二个元素,正如您在list-initialization __m128d{x}中所请求的那样。

  

当源操作数是XMM寄存器时,移动低四字;当目标操作数是XMM寄存器时,四字存储到寄存器的低位四字,高位四字被清除为全0。

请记住,当提供的初始值设定项少于成员时,所有剩余的成员都会进行值初始化(为零)。

我希望更高级别的优化能够看到第二个元素从未使用过,并删除无关的指令。另一方面,即使未使用,在添加操作期间也不允许第二个值陷阱,并且明确地清除它可能是确保它没有的最安全的方法。