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

问题描述 投票:2回答:1

在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不是一种选择。然而,使用+很简单,足以说明这个问题。

c++ simd intrinsics sse2
1个回答
3
投票

正如你在列表初始化movq所要求的那样,“无关的”__m128d正在清除__m128d{x}中的第二个元素。

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

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

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

© www.soinside.com 2019 - 2024. All rights reserved.