SSE(SIMD):通过标量乘以向量

我在程序中执行的常见操作是通过标量缩放矢量(V * s,例如[1,2,3,4] * 2 == [2,4,6,8])。 除了首先在向量中的每个位置加载标量(例如_mm_set_ps(2,2,2,2))然后相乘之外,是否有SSE(或AVX)指令来执行此操作?

这就是我现在所做的:

__m128 _scalar = _mm_set_ps(s,s,s,s); __m128 _result = _mm_mul_ps(_vector, _scalar); 

我在寻找像……

 __m128 _result = _mm_scale_ps(_vector, s); 

根据您的编译器,您可以使用_mm_set1_ps稍微改进代码生成:

 const __m128 scalar = _mm_set1_ps(s); __m128 result = _mm_mul_ps(vector, scalar); 

但是,像这样的标量常量只需要在任何循环之外初始化一次,因此性能成本应该是无关紧要的。 (除非标量值在循环内发生变化?)

与往常一样,您应该查看编译器生成的代码,并尝试在合适的分析器下运行代码,以查看热点的真正位置。

没有用于通过标量乘以向量的指令。 但是,有一些指令用于将相同的标量值加载到向量寄存器中的所有位置。

AVX指令集提供_mm_broadcast_ss / _mm256_broadcast_ss / _mm256_broadcast_sd内在函数,用于使用相同的float / double值填充SSE和AVX寄存器。

在SSE3指令集中,您可能会发现_mm_loaddup_pd内在函数,它使用相同的double值填充SSE寄存器。

在其他版本的SSE中,最佳选择是使用_mm_load_ss / _mm_load_sd加载标量值,然后使用_mm_load_ss / _mm_load_sd将其复制到向量寄存器的所有元素。

我不知道任何单一指令可以做你想要的。 设定操作真的是瓶颈吗? 如果您将一个大向量乘以相同的常量,那么用四个常量副本填充XMM / YMM寄存器所需的时间应该只占总时间的一小部分。

作为一个简单的优化,如果常量是2,就像在你的例子中那样,你可以用add指令代替乘法,而不需要任何常量。