ima*_*ett 6 c++ assembly gcc icc
我想是时候使用快速倒数平方根.所以,我尝试编写一个函数(将inline在生产中标记):
float sqrt_recip(float x) {
return _mm_cvtss_f32( _mm_rsqrt_ss( _mm_set_ps1(x) ) ); //same as _mm_set1_ps
}
Run Code Online (Sandbox Code Playgroud)
TL; DR:我的问题是"如何让GCC和ICC为上述函数输出最小的汇编(两条指令),最好不要求助于原始汇编(坚持使用内在函数)?"
如上所述,在ICC 13.0.1,GCC 5.2.0和Clang 3.7上,输出为:
shufps xmm0, xmm0, 0
rsqrtss xmm0, xmm0
ret
Run Code Online (Sandbox Code Playgroud)
这是有道理的,因为我曾经_mm_set_ps1分散x到寄存器的所有组件中.但是,我真的不需要这样做.我宁愿只做最后两行.当然,shufps只有一个周期.但rsqrtss只有三到五个.这是20%到33%的开销,完全没有价值.
我试过的一些事情:
我试着不设置它:
union { __m128 v; float f[4]; } u;u.f[0] = x;return _mm_cvtss_f32(_mm_rsqrt_ss(u.v));
这实际上适用于Clang,但ICC和GCC的输出尤其令人震惊.
您可以填充零(即使用_mm_set_ss),而不是散射.同样,GCC和ICC的输出都不是最佳的.在海湾合作委员会的案例中,海湾合作委员会搞笑地补充说:
movss DWORD PTR [rsp-12], xmm0
movss xmm0, DWORD PTR [rsp-12]
三年半过去了,虽然编译器已经进步,情况也有所好转,但它们仍然没有输出最佳代码。
然而,在不使用原始汇编的情况下,我们仍然可以通过使用内联汇编比内在函数做得更好。我们必须要小心一些;在非 VEX 编码和 VEX 编码指令之间切换会带来很大的损失,因此我们需要两个代码路径。
这会在 GCC (9.0.1)、Clang (9.0.0) 和 ICC (19.0.1.144) 上产生最佳结果。它仅在内联且未进行 VEX 编码时在 MSVC (19.16) 上产生最佳结果(这可能是我们所能做到的,因为 MSVC 不支持 x86-64 上的内联汇编):
#include <xmmintrin.h>
inline float rsqrt_fast(float x) {
#ifndef _MSC_VER //Optimal
float result;
asm( //Note AT&T order
#ifdef __AVX__
"vrsqrtss %1, %1, %0"
#else
"rsqrtss %1, %0"
#endif
: "=x"(result)
: "x"(x)
);
return result;
#else //TODO: not optimal when in AVX mode or when not inlined
return _mm_cvtss_f32(_mm_rsqrt_ss(_mm_set_ps1(x)));
#endif
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
584 次 |
| 最近记录: |