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

标签 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不是一个选择。但是使用+很简单足以说明问题。

最佳答案

“无关的”movq 正在清除 __m128d 中的第二个元素,按照列表初始化 __m128d{x} 的请求.

When the source operand is an XMM register, the low quadword is moved; when the destination operand is an XMM register, the quadword is stored to the low quadword of the register, and the high quadword is cleared to all 0s.

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

我希望进行更高级别的优化,以确保第二个元素从未被使用,并删除无关的指令。另一方面,即使未使用,第二个值也不能在加法操作期间被捕获,并且显式清除它可能是确保它不会被捕获的最安全方法。

关于c++ - 如何最大限度地减少将 double 加载到使用标量 SIMD 内在函数的 simd 寄存器中的开销,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48055973/

相关文章:

c++ - 修改对象与修改该对象的拷贝

c++ - 如何在 C++ 中准确读取二进制文件中的一个字节

c++ - 添加 SSE 寄存器的组件

ARM NEON : comparing 128 bit values

c++ - SSE 比 FPU 慢?

英特尔 C 编译器使用未对齐的 SIMD 移动和对齐的内存

c++ - 经过一些计算后在基类之后调用参数化构造函数

c - 从 128 位 __m128 Intel Intrinsic 中求和 4 个整数

c++ - SSE2 内在函数在哪里存储结果?

c++ - 使用 C/C++ 获取 HASP key (问题)