我想使用AVX2添加2个无符号向量
__m256i i1 = _mm256_loadu_si256((__m256i *) si1);
__m256i i2 = _mm256_loadu_si256((__m256i *) si2);
__m256i result = _mm256_adds_epu16(i2, i1);
然而,我需要溢出而不是饱和,_mm256_adds_epu16
与非向量化代码相同,是否有任何解决方案?
使用正常二进制换行_mm256_add_epi16
代替饱和式adds
。
2的补码和无符号加减法是相同的二进制操作,这就是现代计算机使用2的补码的原因之一。正如vpaddw
的asm手动条目所提到的,这些指令可以用于有符号或无符号整数。(intrinsic指南条目根本没有提到签名,因此对澄清这种混淆没有多大帮助。)
像_mm_cmpgt_epi32
这样的比较是对签名敏感的,但是数学运算(和cmpeq
)不敏感。
Intel选择的intrinsic名称可能看起来像是专门针对有符号整数的,但他们总是使用epi
或si
来处理在有符号和无符号元素上同样工作的东西。但是不,epu
意味着一个特定的无符号的东西,而epi
可以是特定的有符号的操作,也可以是在有符号和无符号上同样工作的东西。或者签名无关的东西。
例如,_mm_and_si128
是纯位的。_mm_srli_epi32
是一个逻辑右移位,在零中移位,类似于无符号C移位。不是复制符号位,那是_mm_srai_epi32
(右移直接算术)。像_mm_shuffle_epi32
这样的shuffle只是在块中移动数据。
像_mm_mullo_epi16
和_mm_mullo_epi32
这样的非加宽乘法对于有符号和无符号也是一样的。只有高半部分_mm_mulhi_epu16
或扩大倍数_mm_mul_epu32
具有无符号形式,作为其特定符号epi16
/32
形式的对应。
这也是为什么386只添加了一个标量整数imul ecx, esi
形式,而不是mul ecx, esi
形式,因为只有FLAGS设置会不同,而不是整数结果。SIMD操作甚至没有FLAGS输出。
intrinsic指南将_mm_mullo_epi16
描述为符号扩展并产生32位产品,然后截断到低32位。pmullw
的asm手册也将其描述为以这种方式签名,它似乎将其作为带签名的pmulhw
的伴侣来谈论。(并且有一些错误,如描述AVX1VPMULLW xmm1, xmm2, xmm3/m128
形式乘以32位dword元素,可能是pmulld
的复制/粘贴错误)
有时英特尔的命名方案是有限的,比如_mm_maddubs_epi16
是u8 x i8 =>16位扩展乘法,水平添加对(带符号饱和度)。我通常必须查找pmaddubsw
的内在属性,以提醒自己他们根据输出元素宽度而不是输入元素来命名它。输入有不同的符号,所以如果他们必须选择一个,一边,我想它的输出命名是有意义的,与符号饱和可能发生在一些输入,如pmaddwd
。