是否有 SIMD 指令来实现批量数组内存索引映射?

Posted

技术标签:

【中文标题】是否有 SIMD 指令来实现批量数组内存索引映射?【英文标题】:Is there an SIMD instruction to achieve batch array memory index mapping? 【发布时间】:2018-02-26 05:53:42 【问题描述】:

在我的 RGB 到灰色的情况下:

Y = (77*R + 150*G + 29*B) >> 8;

我知道 SIMD (NEON, SSE2) 可以这样做:

foreach 8 elements:
A0,A1,A2,A3,A4,A5,A6,A7 = 77*R0,R1,R2,R3,R4,R5,R6,R7
B0,B1,B2,B3,B4,B5,B6,B7 = 150*G0,G1,G2,G3,G4,G5,G6,G7
C0,C1,C2,C3,C4,C5,C6,C7 = 29*B0,B1,B2,B3,B4,B5,B6,B7
D0,D1,D2,D3,D4,D5,D6,D7 = A0,A1,A2,A3,A4,A5,A6,A7 + B0,B1,B2,B3,B4,B5,B6,B7
D0,D1,D2,D3,D4,D5,D6,D7 = D0,D1,D2,D3,D4,D5,D6,D7 + C0,C1,C2,C3,C4,C5,C6,C7
D0,D1,D2,D3,D4,D5,D6,D7 = D0,D1,D2,D3,D4,D5,D6,D7 >> 8

但是,乘法指令至少需要2个时钟周期,并且R,G,B在[0-255]中, 我们可以使用三个查找表(一个数组,长度=256)来存储部分结果 77*R(标记为 X)、150*G(标记为 Y)、29*B(标记为 Z)。 所以我在找指令可以做的意图:

foreach 8 elements:
A0,A1,A2,A3,A4,A5,A6,A7 = X[R0],X[R1],X[R2],X[R3],X[R4],X[R5],X[R6],X[R7]
B0,B1,B2,B3,B4,B5,B6,B7 = Y[G0],Y[G1],Y[G2],Y[G3],Y[G4],Y[G5],Y[G6],Y[G7]
C0,C1,C2,C3,C4,C5,C6,C7 = Z[B0],Z[B1],Z[B2],Z[B3],Z[B4],Z[B5],Z[B6],Z[B7]
D0,D1,D2,D3,D4,D5,D6,D7 = A0,A1,A2,A3,A4,A5,A6,A7 + B0,B1,B2,B3,B4,B5,B6,B7
D0,D1,D2,D3,D4,D5,D6,D7 = D0,D1,D2,D3,D4,D5,D6,D7 + C0,C1,C2,C3,C4,C5,C6,C7
D0,D1,D2,D3,D4,D5,D6,D7 = D0,D1,D2,D3,D4,D5,D6,D7 >> 8

有什么好的建议吗?

【问题讨论】:

在 NEON 上最多 16 位乘法消耗一个周期。 (至少在 ARMv7 上) 【参考方案1】:

在 AVX2 / AVX512 中没有字节或字聚集指令,在 NEON 中根本没有聚集。确实存在的 DWORD 集合比乘法慢得多!例如根据Agner Fog's instruction table for Skylake,vpgatherdd ymm,[reg + scale*ymm], ymm 的每 5 个周期吞吐量之一。

您可以将随机播放用作并行查表。但是每次查找的表是 256 个 16 位字。那是 512 字节。 AVX512 有一些从 2 个寄存器的串联中选择的 shuffle,但那是“仅”2x 64 字节,它们的字节或字元素大小版本是 multiple uops on current CPUs。 (例如AVX512BW vpermi2w)。不过,与 vpshufb 相比,它们仍然非常强大。

因此,在您的情况下,使用 shuffle 作为 LUT 将不起作用,但在某些情况下它确实非常工作得很好,例如对于 popcount,您可以将字节拆分为 4 位半字节,并使用 vpshufb 从 16 元素字节表中并行进行 32 次查找。

通常对于 SIMD,您希望用计算替换表查找,因为计算对 SIMD 更加友好。


收起它并使用pmullw / _mm_mullo_epi16。您具有指令级并行性,并且 Skylake 对于 16 位 SIMD 乘法具有每个时钟 2 个吞吐量(但 5 个周期延迟)。对于图像处理,通常吞吐量比延迟更重要,只要您将延迟保持在合理范围内,以便乱序执行可以隐藏它。

如果您的乘法器在其二进制表示中的1 位足够少,您可以考虑使用移位/加法而不是实际的乘法。例如B * 29 = B * 32 - B - B * 2。或B<<5 - B<<1 - B。不过,这么多指令可能比单个乘法具有更多的吞吐量成本。如果您只需 2 个术语就可以做到这一点,那可能是值得的。 (但话又说回来,可能仍然不是,这取决于 CPU。总指令吞吐量和向量 ALU 瓶颈是一个大问题。)

【讨论】:

哦,非常感谢!

以上是关于是否有 SIMD 指令来实现批量数组内存索引映射?的主要内容,如果未能解决你的问题,请参考以下文章

双精度数组上的 SIMD?

是否有 SIMD 指令来加快校验和计算?

是否可以使用 SIMD 指令进行 3x3 矩阵求逆?

是否有用于元素部分移位的 simd 指令/内在/内置?

使用 SIMD 指令避免无效的内存加载

内存是矩阵加法(SIMD 指令)的瓶颈吗?