我在程序中执行的常见操作是通过标量缩放矢量(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);
答案 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指令代替乘法,而不需要任何常量。