ARM 机器上的 mm_shuffle_epi8 等效项

Posted

技术标签:

【中文标题】ARM 机器上的 mm_shuffle_epi8 等效项【英文标题】:mm_shuffle_epi8 equivalent on ARM machines 【发布时间】:2021-11-29 10:52:57 【问题描述】:

在一个专注于加速 ARM 性能的项目中, 我正在使用下面页面 https://github.com/f4exb/cm256cc/blob/master/sse2neon.h#L981 中的 mm_shuffle_epi8 实现。

但上述实现不是最优的,会导致性能成本。

ARM 的 _mm_shuffle_epi8 是否有正确的等价物?

【问题讨论】:

我的建议是,如果您需要这种性能,您可能应该对整个功能进行特定于 Arm 的实现。这样就可以更改算法以更好地适应 Arm 指令集。 @Johan 我认为 OP 正在执行特定于 ARM 的实现,并且正在寻找线索。我自己学习了AVX2NEON2SSE 您可能对 [SIMD Everywhere(github.com/simd-everywhere/simde) 感兴趣。除了实现之外,wiki 和文档还链接到其他实现。 【参考方案1】:

vtbl2(可能还有vtbx2)正是您要找的。​​p>

但请注意,这些指令有很长的延迟,尤其是在 Cortex-a57 和 Cortex-a72 上。aarch64 模式)它甚至没有在 A-57 上流水线。

我自己不惜一切代价避免使用它们:太贵了。

NEON 具有优于 AVX 的置换指令。也许你可以找到解决方法。

PS:SSE2NEON.... IMO 根本不是一个好主意。而且您提供的链接的方式非常糟糕。

【讨论】:

谢谢。找到了与 SSE 上的 shuffle 等效的内在 vqtbl1q_u8【参考方案2】:

等价物应该是这样的

uint8x16_t shuffle_epi8(uint8x16_t table, uint8x16_t index) 
   int8x16_t mask = vshrq_n_s8(vreinterpretq_s8_u8(index), 7);
   index = vandq_u8(index, vdupq_n_u8(15));
   index = vqtbl1q_u8(table, index);
   return vbicq_u8(index, vreinterpretq_u8_s8(mask));

在 armv7 上,需要模拟 16 位宽的表

inline uint8x16_t vqtbl1q_u8(uint8x16_t table, uint8x16_t idx) 
    uint8x8x2_t table2vget_low_u8(table), vget_high_u8(table);
    uint8x8_t lo = vtbl2_u8(table2, vget_low_u8(idx));
    uint8x8_t hi = vtbl2_u8(table2, vget_high_u8(idx));
    return vcombine_u8(lo, hi);

【讨论】:

你看到cortex-a8标签了吗? :-) 如果已知索引向量在 0..15 以内,那么只使用 vqtbl1q_u8 函数就足够了。 您应该进行 msb 检查以使其 100% 兼容。是的,这很糟糕,这就是为什么我说 SSE2NEON 不是一个好主意。 MSB 检查从一开始就存在于shuffle_epi8 中。我正在使用vcltq_u8(index, 0x80);,它转换为与立即数的有符号比较。它不需要添加到 vqtbl1q_u8,因为这只是 armv7 的 arm64 仿真。 你不需要vclt。你只需要在 7 之前签名 vshr,然后 vbic

以上是关于ARM 机器上的 mm_shuffle_epi8 等效项的主要内容,如果未能解决你的问题,请参考以下文章

#yyds干货盘点#关于 arm 和 x86 架构的思考

使用硬件计数器测量 ARM Cortex-A8 上的执行时间

关于 arm 和 x86 架构的思考

关于 arm 和 x86 架构的思考

ARM笔记本电脑上的QEMU“tgc致命错误”?

ARM上的Ruby on Rails性能