在 ARMv7a 和 Neon 上通过 64 位签名比较支持 CMGT 的最有效方法是什么?

What is the most efficient way to support CMGT with 64bit signed comparisons on ARMv7a with Neon?

这个问题最初是为 提出的。由于每个算法都与 ARMv7a+NEON 对相同操作的支持重叠,因此更新了问题以包括 ARMv7+NEON 版本。应评论者的要求,在此提出这个问题,以表明它确实是一个单独的主题,并提供可能对 ARMv7+NEON 更实用的替代解决方案。这些问题的最终目的是找到 WebAssembly SIMD 考虑的理想实现。

从原来的post,在ARMv7+NEON上实现的最佳x64/SSE2算法工作原理如下:

对于前 32 位相等且 a[0:31] > b[0:31] 的每种情况,

(a[32:63] === b[32:63]) & (b[0:63] - a[0:63]) 都会产生掩码 0xFFFFFFFF.........。在所有其他情况下,例如前 32 位不相等或 a[0:31]< b[0:31],它 returns 0x0。如果前 32 位无关紧要,而下 32 位很重要,则这具有将每个整数的底部 32 位作为掩码传播到高 32 位的效果。对于其余情况,它比较前 32 位并将它们组合在一起。例如,如果 a[32:63] > b[32:63],则无论最低有效位如何,a 肯定大于 b。最后,它swizzles/shuffles/transposes每个64位掩码的高32位到低32位产生一个完整的64位掩码。

说明性示例实现在此 Godbolt

带符号的 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;
}