yadhu
yadhu

Reputation: 1333

How conditionally negate an AVX2 int16_t vector based on another vector of 0 or 1 elements?

I have a vector int16_t beta = {1,1,0,0,0,0,0,0}.

I want to implement this equation with AVX2

enter image description here

c[i] = a[i] + (-1)^beta[i] * b[i]

where a, b, c, and beta are all AVX2 vectors of int16_t.


I have figured out that, if I can map 1 to -32768 multiplication operation can be avoided. I mean, flipping the sign of vector b can be done using OR and NEGATE functions of simd intrinsics.

I do know that 1 can be mapped to -32768 using left shift operation, however avx2 doesn't have any bit shift operations1. Is there any way to efficiently map 1 to -32768 with simd?


Editor's footnote 1: _mm256_slli_epi16(x, 15) does in fact exist. But there are other ways to implement the whole formula so the question is interesting after all.

Upvotes: 1

Views: 1008

Answers (2)

user555045
user555045

Reputation: 64903

There is a quick way to conditionally negate, using _mm256_sign_epi16. The mask is not of the right form, but it can be transformed into the right form by adding 0x7FFF to every element, so:

__m256i masks = _mm256_add_epi16(beta, _mm256_set1_epi16(0x7FFF));
__m256i res = _mm256_add_epi16(a, _mm256_sign_epi16(b, masks));

Upvotes: 4

Max Langhof
Max Langhof

Reputation: 23701

You can transform

c[i] = a[i] + (-1)^beta[i] * b[i]

to

c[i] = a[i] - (beta[i] AND b[i]) + ((NOT beta[i]) AND b[i])

as the original formula translates to "subtract this bit if beta[i] is set, otherwise add it".
(I have no idea what you intend to happen for c[i] = 0 + (-1) * 1 or c[i] = 1 + 1 * 1 - I'm assuming normal arithmetic addition with carries here, contrary to the index notation).
So you can just drop the indices:

c = a - (beta & b) + (!beta & b)

I don't know if that has a good mapping to AVX2 intrinsics but I would suspect it does.

Upvotes: 0

Related Questions