_mm_broadcast_ss()
和_mm_load_ps1()
之间有什么区别?
void example(){
__declspec(align(32)) const float num = 20;
__m128 a1 = _mm_broadcast_ss(&num);
__declspec(align(32)) float f1[4];
_mm_store_ps (f1, a1);
std::cout << f1[0] << " " << f1[1] <<" " << f1[2] << " " << f1[3] << "\n";
__m128 a2 = _mm_load_ps1(&num);
__declspec(align(32)) float f2[4];
_mm_store_ps (f2, a2);
std::cout << f2[0] << " " << f2[1] <<" " << f2[2] << " " << f2[3] << "\n";
}
我两种方式都有相同的输出,那为什么它们都存在?
答案 0 :(得分:7)
_mm_broadcast_ss
仅针对AVX目标进行编译。
_mm_load1_ps
/ _mm_load_ps1
将编译为多个指令(movss
/ shufps
)。当 为AVX目标进行编译时,任何好的编译器都会使用vbroadcastss
来实现它们。
load1
/ set1
和其他便利功能,因为让编译器选择最佳策略来移动数据通常是好事。
_mm_broadcast_*
内在函数是作为vbroadcastss
/ vbroadcastsd
指令的直接包装引入的。 (AVX2具有整数vpbroadcast...
,而reg-reg形式为vbroadcastss
。AVX1仅具有vbroadcastss x/ymm, [mem]
。)
_mm_load1_ps
或_mm_set1_ps
没有任何缺点。它对代码没有任何影响,并为非AVX目标提供相同的源代码。
选择可能会对-O0
的asm输出产生影响,但IDK会有所不同。如果你关心未优化构建中的asm输出,那么1:这很奇怪,2:你必须看看你的编译器做了什么。
正如你从godbolt上的asm输出中看到的那样(对于gcc):
-mno-avx
)bcast: compile error so I #ifdef it out
__m128 load1(const float*p) { return _mm_load1_ps(p); }
movss xmm0, DWORD PTR [rdi]
shufps xmm0, xmm0, 0
ret
-mavx
)__m128 bcast(const float*p) { return _mm_broadcast_ss(p); }
vbroadcastss xmm0, DWORD PTR [rdi]
ret
__m128 load1(const float*p) { return _mm_load1_ps(p); }
vbroadcastss xmm0, DWORD PTR [rdi]
ret