有没有实现批量数组内存索引映射的SIMD指令?

Is there an SIMD instruction to achieve batch array memory index mapping?

在我的 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个时钟周期,而[0-255]中的R,G,B, 我们可以使用三个查找 table(一个数组,长度=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

有什么好的建议吗?

AVX2 / AVX512 中没有字节或字聚集指令,NEON 中根本没有聚集。确实存在的 DWORD 集合比乘法慢得多!例如根据 Agner Fog's instruction table for Skylake.

vpgatherdd ymm,[reg + scale*ymm], ymm 每 5 个周期吞吐量一个

您可以将随机播放作为并行使用 table-lookup。但是每次查找的 table 是 256 个 16 位字。那是 512 字节。 AVX512 有一些洗牌 select 来自 2 个寄存器的串联,但那是 "only" 2x 64 字节,并且那些的字节或字 element-size 版本是 . (e.g. AVX512BW vpermi2w)。不过,与 vpshufb 相比,它们仍然非常强大。

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

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


吸干它并使用 pmullw / _mm_mullo_epi16。您具有 instruction-level 并行性,而 Skylake 对于 16 位 SIMD 乘法具有每个时钟 2 个吞吐量(但有 5 个周期延迟)。对于图像处理,通常吞吐量比延迟更重要,只要您将延迟保持在合理范围内,以便 out-of-order 执行可以隐藏它。

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