load1和广播内在函数之间的区别

Ste*_*nov 4 x86 sse simd intrinsics

_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";
}
Run Code Online (Sandbox Code Playgroud)

我两种方式都有相同的输出,那么为什么它们都存在?

Pet*_*des 7

_mm_broadcast_ss 仅编译AVX目标.

_mm_load1_ps/ _mm_load_ps1将在编译不支持AVX的目标时编译为多个指令(movss/ shufps).当你正在编写一个AVX的目标,任何好的编译器将使用vbroadcastss来实现它们.

load1/ set1和其他便利函数在早期就已经引入,因为让编译器选择最佳的数据移动策略通常是好的.

_mm_broadcast_*内在函数是作为vbroadcastss/ vbroadcastsd指令的直接包装引入的.(AVX2有整数vpbroadcast...,vbroadcastss只有.AVX1 的reg-reg形式vbroadcastss x/ymm, [mem].)


AFAICT,使用_mm_load1_ps或没有任何缺点_mm_set1_ps.

它对代码没有任何影响,并为非AVX目标提供相同的源代码构建.

选择可能会对asm输出产生影响-O0,但是IDK.如果你关心未优化构建中的asm输出,那么1:这很奇怪,2:你必须看看你的编译器做了什么.


正如你从godbolt上的asm输出中看到的那样(对于gcc):

没有AVX(-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
Run Code Online (Sandbox Code Playgroud)

使用AVX(-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
Run Code Online (Sandbox Code Playgroud)