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

时间:2012-01-31 12:35:01

标签: c x86 sse simd

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

这就是我现在所做的:

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

我正在寻找类似......

的东西
__m128 _result = _mm_scale_ps(_vector, s);

3 个答案:

答案 0 :(得分:13)

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

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

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

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

答案 1 :(得分:4)

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

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_shuffle_ps / {{的向量寄存器的所有元素1}}。

答案 2 :(得分:1)

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

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