如何最大限度地减少使用标量 SIMD 内部函数的 SIMD 注册表的双重负载开销
how to minimize overhead loading double into simd regsiters working with scalar SIMD intrinsics
使用 gcc 7.2 在 godbolt.org 我可以看到以下代码在汇编程序中进行了非常优化的翻译。我看到 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
但是,如果我尝试使用下面的代码使用内部函数和模板来实现相同的目标,我可以看到增加了一些开销。特别是,指令的重点是什么: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
编译器将结果转换为布尔值,而内部函数会将其保留为双位掩码。因此,对于我的用例,编写x<y
不是一种选择。然而,使用+
很简单,可以说明这个问题。
"无关"movq
是清除__m128d
中的第二个元素,正如列表初始化__m128d{x}
所要求的那样。
当源操作数是 XMM 寄存器时,移动低四字;当目标操作数是 XMM 寄存器时,四字存储到寄存器的低四字,高四字清除到所有 0。
请记住,当提供的初始值设定项少于成员数量时,所有剩余成员都将进行值初始化(为零(。
我希望进行更高级别的优化,以确保从未使用第二个元素,并删除无关的指令。 另一方面,即使未使用,在加法操作期间也不允许捕获第二个值,显式清除它可能是确保它不会捕获的最安全方法。
相关文章:
- C++ SSE 内部函数:将结果存储在变量中
- C++代码停止工作错误使用cout内部函数
- 为什么从具有较大阵列的 SIMD 内部函数中获得的相对加速比标量更大?
- 使用英特尔内部函数 (AVX) 中的混合说明
- 英特尔汇编与内部函数,AVX
- 使用SSE内部函数复制少量数据时出现问题
- 在为函数编写单元测试时,我应该模拟所做的内部函数调用吗?
- 用于平铺矩阵乘法的 AVX 内部函数
- 是否可以使用类的析构函数内部函数来重置值?
- 我在理解 AVX 随机内部函数如何为 8 位时遇到一些问题
- 无法执行内部函数 strlen
- COUT 内部函数调用的顺序
- GCC(通过 CUDA)内部函数的编译器错误,但我没有使用任何
- C++ ld 链接器 --wrap 选项不适用于内部函数调用
- 通过Visual Studio将小型结构逐值传递到非内部函数的速度很慢
- 在使用英特尔内部函数对 SIMD 代码进行编程时,如何强制使用 vmovapd 而不是 vmovupd?
- 如何最大限度地减少使用标量 SIMD 内部函数的 SIMD 注册表的双重负载开销
- 通过内部函数或指令手动控制英特尔 MIC SIMD 操作
- 与SIMD内部函数进行比较和交换
- 当使用SIMD内部函数时,如何在寄存器中保留与输入相关的热数据