在 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 寄存器进行位移?

如何访问 NEON 指令中的完整 128 位?

Aarch64 NEON 中的 UADDL 与 UADDL2

Debug系列aarch64下unrecognized command line option ‘-mfpu=neon‘

对于 ARM Aarch64 的 NEON 编码,如何将寄存器推送到堆栈?似乎 STMFD 不是 Aarch64 指令集的一部分?