当我需要执行一个向量操作,其操作数只是一个广播到每个组件的一个浮点数时,我应该预先计算__m256或__m128,并在需要时加载它,或者每次我使用_mm_set1_ps将浮点数广播到寄存器需要矢量?
我一直在预先计算非常重要和高度使用的向量,并在运行中生成那些不太重要的向量.但我真的通过预先计算获得了任何速度吗?这值得吗?
_mm_set1_ps是用单个指令实现的吗?这可能会回答我的问题.
解决方法
当然,它将依赖于您的代码,但我已经使用这两种方法实现了两个简单的函数.
See code
__m128 calc_set1(float num1,float num2) { __m128 num1_4 = _mm_set1_ps(num1); __m128 num2_4 = _mm_set1_ps(num2); __m128 result4 = _mm_mul_ps(num1_4,num2_4); return result4; } __m128 calc_mov(float* num1_4_addr,float* num2_4_addr) { __m128 num1_4 = _mm_load_ps(num1_4_addr); __m128 num2_4 = _mm_load_ps(num2_4_addr); __m128 result4 = _mm_mul_ps(num1_4,num2_4); return result4; }
和装配
calc_set1(float,float): shufps $0,%xmm0,%xmm0 shufps $0,%xmm1,%xmm1 mulps %xmm1,%xmm0 ret calc_mov(float*,float*): movaps (%rdi),%xmm0 mulps (%rsi),%xmm0 ret
您可以看到calc_mov()按照您的预期执行,calc_set1()使用单个shuffle指令.
如果在高速缓存未命中的罕见事件中L1高速缓存的加载端口更忙,则movps指令可以花费大约四个周期来生成更多地址.
shufps将在最近的任何英特尔微体系结构上进行一个周期.无论是SSE128还是AVX256,我都相信这是真的.因此我建议使用mm_set1_ps方法.
当然,shuffle指令假定float已经在SSE / AVX寄存器中.如果您从内存加载它,那么广播将更好,因为它将在单个指令中捕获最好的movps和shufps.