【问题标题】:Is there a way to subtract packed unsigned doublewords, saturated, on x86, using MMX/SSE?有没有办法在 x86 上使用 MMX/SSE 减去压缩的无符号双字?
【发布时间】:2019-10-24 20:03:46
【问题描述】:

我一直在研究 MMX/SSE,我想知道。有无符号字节和字的压缩饱和减法指令,但不是双字。

有没有办法做我想做的事,或者如果没有,为什么没有?

【问题讨论】:

  • 您可以使用比较和掩码。至于为什么它不作为单个指令存在,这是任何人的猜测。
  • 您的源值是有符号还是无符号?如果输入是无符号的,这相当容易,如果它们是有符号的,那就有点棘手了。
  • 查看 LLVM 如何自动矢量化 Rust u32.saturating_sub(): godbolt.org/z/huP4PX - range-shift 使用 PXOR 进行签名,然后使用 PCMPGTD 进行签名比较,然后使用 AND/ANDN/OR 对 PSUBD 应用饱和度结果。我不确定这是最优的;它应该只需要 PAND,因为无符号减法的唯一饱和情况是饱和到 0。
  • 您可以使用subus(a, b) == max(a, b) - b - E:SSE4.1 很好,MMX/SSE 是不是字面上只有 MMX 和 SSE 的意思?
  • @harold:哦,是的,对于pmaxud,SSE4.1 非常好。

标签: assembly x86 sse mmx saturation-arithmetic


【解决方案1】:

如果您有可用的 SSE4.1,我认为您不会比使用 @harold 建议的 pmaxud+psubd 方法更好。有了 AVX2,当然也可以使用对应的 256bit 变种。

__m128i subs_epu32_sse4(__m128i a, __m128i b){
    __m128i mx = _mm_max_epu32(a,b);
    return _mm_sub_epi32(mx, b);
}

如果没有 SSE4.1,您需要以某种方式比较两个参数。不幸的是,没有 epu32 比较(不是在 AVX512 之前),但您可以通过首先将 0x80000000(在这种情况下相当于 xor-ing)添加到两个参数来模拟一个:

__m128i cmpgt_epu32(__m128i a, __m128i b) {
    const __m128i highest = _mm_set1_epi32(0x80000000);
    return _mm_cmpgt_epi32(_mm_xor_si128(a,highest),_mm_xor_si128(b,highest));
}

__m128i subs_epu32(__m128i a, __m128i b){
    __m128i not_saturated = cmpgt_epu32(a,b);
    return _mm_and_si128(not_saturated, _mm_sub_epi32(a,b));
}

在某些情况下,可能最好将比较替换为对最高位进行一些位旋转并使用移位将其广播到每个位(这替换了 pcmpgtd 和三位-由psrad 和五个位逻辑操作进行的逻辑操作(并且必须至少加载一次0x80000000):

__m128i subs_epu32_(__m128i a, __m128i b) {
    __m128i r = _mm_sub_epi32(a,b);
    __m128i c = (~a & b) | (r & ~(a^b)); // works with gcc/clang. Replace by corresponding intrinsics, if necessary (note that `andnot` is a single instruction)
    return _mm_srai_epi32(c,31) & r;
}

Godbolt-Link,还包括adds_epu32 变体:https://godbolt.org/z/n4qaW1 奇怪的是,对于非 SSE4.1 变体,clang 需要比 gcc 更多的寄存器副本。另一方面,当使用 SSE4.1 编译时,clang 找到了针对 cmpgt_epu32 变体的 pmaxud 优化:https://godbolt.org/z/3o5KCm

【讨论】:

    猜你喜欢
    • 2021-02-11
    • 1970-01-01
    • 1970-01-01
    • 2023-03-14
    • 2010-12-05
    • 1970-01-01
    • 1970-01-01
    • 2021-06-27
    • 1970-01-01
    相关资源
    最近更新 更多