Assembly SSE4.1带溢出的无符号整数比较

Assembly SSE4.1带溢出的无符号整数比较,assembly,x86,simd,sse2,sse4,Assembly,X86,Simd,Sse2,Sse4,考虑到16位无符号加法(\u mm\u add\u epi16())可能会溢出,是否有任何方法执行类似于C>=(a+B)与SSE2/4.1指令的比较 代码片段如下所示- #define _mm_cmpge_epu16(a, b) _mm_cmpeq_epi16(_mm_max_epu16(a, b), a) __m128i *a = (__m128i *)&ptr1; __m128i *b = (__m128i *)&ptr2; __m128i *c = (__m128i *)

考虑到16位无符号加法(
\u mm\u add\u epi16()
)可能会溢出,是否有任何方法执行类似于C>=(a+B)与SSE2/4.1指令的比较

代码片段如下所示-

#define _mm_cmpge_epu16(a, b) _mm_cmpeq_epi16(_mm_max_epu16(a, b), a)

__m128i *a = (__m128i *)&ptr1;
__m128i *b = (__m128i *)&ptr2;
__m128i *c = (__m128i *)&ptr3;
            
_m128i xa = _mm_lddqu_si128(a);
_m128i xb = _mm_lddqu_si128(b);
_m128i xc = _mm_lddqu_si128(c);

_m128i res = _mm_add_epi16(xa, xb);
_m128i xmm3 = _mm_cmpge_epu16(xc, res);

问题在于,当16位加法溢出(环绕)时,大于比较会导致误报。我不能用饱和加法来达到我的目的。我在这里研究了检测无符号加法溢出的机制。但是如何使用if进行大于比较。

以下是一些合理的方法:

#include <cstdint>
using v8u16 = uint16_t __attribute__((vector_size(16)));

v8u16 lthsum1(v8u16 a, v8u16 b, v8u16 c) {
    return (c >= a) & (c - a >= b);
}

v8u16 lthsum2(v8u16 a, v8u16 b, v8u16 c) {
    return (a + b >= a) & (a + b <= c);
}
#包括
使用v8u16=uint16\u t\u属性(向量大小(16));
v8u16 lthsum1(v8u16 a、v8u16 b、v8u16 c){
返回(c>=a)和(c-a>=b);
}
v8u16 lthsum2(v8u16 a、v8u16 b、v8u16 c){

return(a+b>=a)&(a+b根据指令集中的可用信息构建缺少的原语。 这里有一个可能的实现,未经测试


我认为你应该首先根据你链接的问题检查溢出。如果你检测到溢出,你就知道
C>(A+B)
是假的。否则,下一步检查。因为你在做向量,你可能必须执行这两个检查,并使用位运算合并它们。(编辑以修复反向条件).你想检查
C>(A+B)
还是
C>=(A+B)
?在第一种情况下,我看不出饱和加法是如何导致误报的。编辑-其C>=(A+B)我认为
C-A>=B
(使用饱和减法)应该有效(未经测试)。编辑:否(需要进一步考虑)@彼得命令是的,
C-A>=B
如果
B>0
C>=A
中的一个得到保证,那么
C-A>=B
技巧就会起作用。(当然,与
C-B>=A
类似)。可以检查
C-min(A,B)>=max(A,B)
如果我计算正确的话,这将是5 uops。当c为0xFFFF且a+b溢出时,这只是一个需要处理的角落案例。@Kaustubh你是什么意思?谢谢。这是我测试中的一个问题。这是我的验收答案。
// Compare uint16_t lanes for a >= b
inline __m128i cmpge_epu16( __m128i a, __m128i b )
{
    const __m128i max = _mm_max_epu16( a, b );
    return _mm_cmpeq_epi16( max, a );
}

// Compare uint16_t lanes for c >= a + b, with overflow handling
__m128i cmpgeSum( __m128i a, __m128i b, __m128i c )
{
    // Compute c >= a + b, ignoring overflow issues
    const __m128i sum = _mm_add_epi16( a, b );
    const __m128i ge = cmpge_epu16( c, sum );

    // Detect overflow of a + b
    const __m128i sumSaturated = _mm_adds_epu16( a, b );
    const __m128i sumInRange = _mm_cmpeq_epi16( sum, sumSaturated );

    // Combine the two
    return _mm_and_si128( ge, sumInRange );
}