在 ARMv7a 上与 Neon 进行 64 位签名比较支持 CMGT 的最有效方法是啥?
Posted
技术标签:
【中文标题】在 ARMv7a 上与 Neon 进行 64 位签名比较支持 CMGT 的最有效方法是啥?【英文标题】:What is the most efficient way to support CMGT with 64bit signed comparisons on ARMv7a with Neon?在 ARMv7a 上与 Neon 进行 64 位签名比较支持 CMGT 的最有效方法是什么? 【发布时间】:2020-12-07 23:45:12 【问题描述】:这个问题最初是为SSE2 here 提出的。由于每个算法都与 ARMv7a+NEON 对相同操作的支持重叠,因此更新了问题以包括 ARMv7+NEON 版本。应评论者的要求,在此处提出此问题以表明它确实是一个单独的主题,并提供可能对 ARMv7+NEON 更实用的替代解决方案。这些问题的最终目的是找到考虑到 WebAssembly SIMD 的理想实现。
【问题讨论】:
【参考方案1】:有符号 64 位饱和减法。
假设我使用 _mm_subs_epi16
的测试是正确的,并转换为 1:1 到 NEON...
uint64x2_t pcmpgtq_armv7 (int64x2_t a, int64x2_t b)
return vreinterpretq_u64_s64(vshrq_n_s64(vqsubq_s64(b, a), 63));
这肯定是模仿 pcmpgtq
的最快的可行方法。
Hacker's Delight的免费章节 给出以下公式:
// return (a > b) ? -1LL : 0LL;
int64_t cmpgt(int64_t a, int64_t b)
return ((b & ~a) | ((b - a) & ~(b ^ a))) >> 63;
int64_t cmpgt(int64_t a, int64_t b)
return ((b - a) ^ ((b ^ a) & ((b - a) ^ b))) >> 63;
【讨论】:
关于 Webassembly 的问题,如果这些解决方案中的任何一个比标量化更有效。你有办法找出来吗? x64 似乎没有 64 位的饱和减法,也没有便携式 psraq。但是,有没有这样的解决方案比最好的 sse2 解决方案更快或更可行? @DanWeber,对于 SSE2,我唯一能想到的就是滥用浮点指令..._mm_cmpge_pd()
等。
官方提案中引用了此答案以支持 NEONv7 签名支持。 github.com/WebAssembly/simd/pull/412#issue-544657198【参考方案2】:
从原帖来看,在 ARMv7+NEON 上实现的最佳 x64/SSE2 算法的工作原理如下:
(a[32:63] === b[32:63]) & (b[0:63] - a[0:63])
为前 32 位相等且 a[0:31] > b[0:31]
的每种情况生成 0xFFFFFFFF.........
的掩码。在所有其他情况下,例如前 32 位不相等或a[0:31]< b[0:31]
,它返回0x0
。如果前 32 位无关紧要,而低 32 位很重要,则这具有获取每个整数的低 32 位并将它们传播到高 32 位作为掩码的效果。对于其余情况,它会比较前 32 位并将它们组合在一起。例如,如果 a[32:63] > b[32:63],那么无论最低有效位如何,a 肯定大于 b。最后,它将每个 64 位掩码的高 32 位转换/混洗/转置到低 32 位,以生成完整的 64 位掩码。
Godbolt 中有一个说明性示例实现。
【讨论】:
考虑用vshr.s64
替换vtrn.32
。
vbsl
的成本是多少,它应该取代and/or
吗?
我不确定。我似乎无法让 llvm mca 与 ARMv7 一起正常工作。以上是关于在 ARMv7a 上与 Neon 进行 64 位签名比较支持 CMGT 的最有效方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章
Xcode11 Swift5 框架不包含模拟器的头文件,仅适用于 arm64 和 armv7a
ARM NEON:如何对整个 64 位 d 寄存器进行位移?
Aarch64 NEON 中的 UADDL 与 UADDL2
Debug系列aarch64下unrecognized command line option ‘-mfpu=neon‘
对于 ARM Aarch64 的 NEON 编码,如何将寄存器推送到堆栈?似乎 STMFD 不是 Aarch64 指令集的一部分?