【发布时间】:2021-11-04 00:44:38
【问题描述】:
我想知道是否有一种将int8 数组相乘的快速方法,即
for(i = 0; i < n; ++i)
z[i] = x * y[i];
我看到Intel intrinsics guide 列出了几个 SIMD 指令,例如 _mm_mulhi_epi16 和 _mm_mullo_epi16,它们对 int16 执行类似的操作。 int8 有没有类似的东西我错过了?
【问题讨论】:
-
你没有错过它,它真的不存在
-
对于任意常量,您可以解压缩为 16 位元素。对于常量,您可以将其分解为移位并加减。 (可以使用
_mm_slli_epi32和_mm_and_si128模拟一个常数的 8 位移位,并使用适当的掩码。) -
如果您想在完成后对 z[] 进行水平求和,您可以使用
pmaddubsw进行 8 位乘法 -> 将对水平添加到 16 位累加器中。 (但它是有符号 x 无符号的,因此使用起来很棘手,除非您知道其中一个输入是有符号的。) -
好吧,不管它的价值如何,用最高优化编译它会使 gcc 和 clang 反汇编看起来像某种克林贡语言。 godbolt.org/z/saGWh8EnW。在我进行一些认真的基准测试之前,我会三思而后行,然后再用一些手动优化来挑战这个邪恶的混乱。
-
@Lundin:它只是将 2x
pmullw=>pand/packuswb解压缩为 16 位元素(扩展为零,因为它会再次截断)(打包回字节,截断,所以无符号饱和度不做任何事情)。至少这是我的假设;这是一种有意义的策略,并且与现有的说明兼容。 Aki 的回答完成了相同的工作,但拆包和重新打包的效率更高。 (链接中的 clang 输出非常复杂,因为它是由 2 个向量展开的。-fno-unroll-loops便于识别 auto-vec 策略。)