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)
。如果没有BMI2
pext
,您可能只需将位图与零交错,因此每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位比较结果向量转换为位图
。如果没有BMI2
pext
,您可能只需将位图与零交错,这样每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是的,对,我忽略了。回答很好!