C++ 如何基于0或1元素的另一个向量有条件地对AVX2 int16_t向量求反?
我有一个向量C++ 如何基于0或1元素的另一个向量有条件地对AVX2 int16_t向量求反?,c++,optimization,simd,avx,avx2,C++,Optimization,Simd,Avx,Avx2,我有一个向量int16_t beta={1,1,0,0,0,0} 我想用AVX2实现这个等式 其中a、b、c和beta都是int16\u t的AVX2向量 我发现,如果我能将1映射到-32768,那么乘法运算就可以避免。我的意思是,翻转向量b的符号可以使用simd内部函数的或和求反函数来完成 我知道可以使用左移位操作将1映射到-32768,但是avx2没有任何位移位操作1。有没有办法用simd有效地将1映射到-32768 编者注1:事实上确实存在。但是,还有其他方法可以实现整个公式,所以这
int16_t beta={1,1,0,0,0,0}
我想用AVX2实现这个等式
其中a、b、c和beta都是int16\u t
的AVX2向量
我发现,如果我能将1映射到-32768,那么乘法运算就可以避免。我的意思是,翻转向量b的符号可以使用simd内部函数的或和求反函数来完成 我知道可以使用左移位操作将1映射到-32768,但是avx2没有任何位移位操作1。有没有办法用simd有效地将1映射到-32768
编者注1:事实上确实存在。但是,还有其他方法可以实现整个公式,所以这个问题毕竟很有趣。您可以转换
c[i] = a[i] + (-1)^beta[i] * b[i]
到
正如原始公式翻译为“如果设置了beta[i],则减去该位,否则添加它”。(我不知道你对
c[I]=0+(-1)*1
或c[I]=1+1*1
会发生什么-我在这里假设带进位的正常算术加法,与索引符号相反)。因此,您可以直接删除索引:
c = a - (beta & b) + (!beta & b)
我不知道它是否能很好地映射到AVX2内部函数,但我怀疑它能
c[i] = a[i] + (-1)^beta[i] * b[i]
到
正如原始公式翻译为“如果设置了beta[i],则减去该位,否则添加它”。(我不知道你对
c[I]=0+(-1)*1
或c[I]=1+1*1
会发生什么-我在这里假设带进位的正常算术加法,与索引符号相反)。因此,您可以直接删除索引:
c = a - (beta & b) + (!beta & b)
我不知道它是否能很好地映射到AVX2内部函数,但我怀疑它能很好地映射到AVX2内部函数。有一种快速的方法可以使用
\u mm256\u sign\u epi16
进行条件求反。掩码的形式不正确,但可以通过向每个元素添加0x7FFF将其转换为正确的形式,因此:
__m256i masks = _mm256_add_epi16(beta, _mm256_set1_epi16(0x7FFF));
__m256i res = _mm256_add_epi16(a, _mm256_sign_epi16(b, masks));
有一种快速的方法可以使用
\u mm256\u sign\u epi16
进行条件否定。掩码的形式不正确,但可以通过向每个元素添加0x7FFF将其转换为正确的形式,因此:
__m256i masks = _mm256_add_epi16(beta, _mm256_set1_epi16(0x7FFF));
__m256i res = _mm256_add_epi16(a, _mm256_sign_epi16(b, masks));
我不确定我是否完全理解你的问题,但也许答案是
\u mm256\u slli\u epi16(x,15)
?你希望beta
有多少位?8或16?将b[i]
和-b[i]
混合在一起可能会使人感兴趣。要对向量求反,请从0中减去它<代码>\uuuum256i负=\uMM256\uSub\uEPI16(\uMM256\uSetZero\uSI256(),输入向量)代码>x86没有SIMD否定指令@wim:您可以将a[i]-b[i]
与a[i]+b[i]
混合。不管是否如此,我认为哈罗德的答案更好。在英特尔CPU上,它是高效的,因此您可以使用无符号位图8=\u mm256\u movemask\u epi8
/位图16=\u pext\u u32(位图8,0baaaaaaa)
。如果没有BMI2pext
,您可能只需将位图与零交错,因此每16个元素有32位,每对元素的低位都是垃圾(或者将其屏蔽为0
,或者使其始终与有效位匹配)。我不确定是否完全理解您的问题,但答案可能是\u mm256\u slli\u epi16(x,15)
?您希望beta
有多少位?8位还是16位?更多\u mm256\u blendv\u epi8
可以在b[i]
和-b[i]
之间混合。若要对向量求反,请将其从0中减去。\u m256i neg=\u mm256\u sub epi16(\u mm256\u setzero\u si256(),input\u vector);
x86没有SIMD否定指令。@wim:您可以将a[i]-b[i]
与a[i]+b[i]混合使用
。或者不,我认为哈罗德的答案更好。在英特尔CPU上,这是高效的,因此您可以使用无符号位图8=\u mm256\u movemask\u epi8
/位图16=\u pext\u u32(位图8,0baaaaaaa)将16位比较结果向量转换为位图
。如果没有BMI2pext
,您可能只需将位图与零交错,这样每16个元素就有32位,每对元素的低位都是垃圾(或将其屏蔽为0
,或使其始终与有效位匹配)。但是掩码
在这里是负数还是零,不是吗?虽然我们需要掩码
是正数还是负数?然而,\u mm256\u sign\u epi16
在这种情况下是个好主意。@wim:masks是0或1。因此我们得到0x7FFF
(正数)或0x8000
(负数)。如果掩码
来自cmpeq
或其他内容,并且是0或所有(-1
=0xffff
),您可能希望添加0x8000
以获得0x7fff
或0x8000
。或者从中减去masks
以获得相反的映射。@PeterCordes是的,对,我忽略了这一点。答案很好!但是masks
在这里是负数或零,不是吗?虽然我们需要masks
是正数或负数,但没有任何问题s、 \u mm256\u sign\u epi16
在这种情况下是个好主意。@wim:masks是0或1。因此我们得到0x7FFF
(正)或0x8000
(负)。如果masks
来自cmpeq
或其他东西,并且是0或所有(-1
=0xffff
),您可能希望添加0x8000
以获得0x7fff
或0x8000
。或者从中减去掩码以获得相反的映射。@PeterCordes是的,对,我忽略了。回答很好!