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

时间:2016-03-24 01:30:06

标签: 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";
}

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

1 个答案:

答案 0 :(得分:7)

_mm_broadcast_ss仅针对AVX目标进行编译。

在编译不支持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]。)

AFAICT,使用_mm_load1_ps_mm_set1_ps没有任何缺点。

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

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

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

Without 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

With 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