I have a __m256i
vector containing 16x16-bit elements.I want to apply a three adjacent horizontal addition on it. In scalar mode I use the following code:
unsigned short int temp[16];
__m256i sum_v;//has some values. 16 elements of 16-bit vector. | 0 | x15 | x14 | x13 | ... | x3 | x2 | x1 |
_mm256_store_si256((__m256i *)&temp[0], sum_v);
output1 = (temp[0] + temp[1] + temp[2]);
output2 = (temp[3] + temp[4] + temp[5]);
output3 = (temp[6] + temp[7] + temp[8]);
output4 = (temp[9] + temp[10] + temp[11]);
output5 = (temp[12] + temp[13] + temp[14]);
// Dont want the 15th element
Because this part is placed in the bottleneck section of my program, I decided to vectorize is using AVX2. Dreamy I can add them like the following pseudo:
sum_v //| 0 | x15 | x14 | x13 |...| x10 |...| x7 |...| x4 |...| x1 |
sum_v1 = sum_v >> 1*16 //| 0 | 0 | x15 | x14 |...| x11 |...| x8 |...| x5 |...| x2 |
sum_v2 = sumv >> 2*16 //| 0 | 0 | 0 | x15 |...| x12 |...| x9 |...| x6 |...| x3 |
result_vec = add_epi16 (sum_v,sum_v1,sum_v2)
//then I should extact the result_vec to outputs
Adding them vertically will provide the answer.
But unfortunately, AVX2 has not a shift operation for 256 bits while the 256-bit register is viewed as two 128-bit lanes. I should use permutation for this case. But I could not find an appropriate permut
, shuffle
, etc. to do this. Is there any suggestion for this implementation that should be as fast as possible.
Using gcc
, linux mint
, intrinsics
, skylake
.
You can try to use something like this:
#include <immintrin.h>
#include <iostream>
template<class T> inline void Print(const __m256i & v)
{
T b[sizeof(v) / sizeof(T)];
_mm256_storeu_si256((__m256i*)b, v);
for (int i = 0; i < sizeof(v) / sizeof(T); i++)
std::cout << int(b[i]) << " ";
std::cout << std::endl;
}
template<int shift> inline __m256i Shift(const __m256i & a)
{
return _mm256_alignr_epi8(_mm256_permute2x128_si256(a, _mm256_setzero_si256(), 0x31), a, shift * 2);
}
int main()
{
__m256i v0 = _mm256_setr_epi16(1,2,3,4,5,6,7,8,9,10,11,12,13,14,15, 0);
__m256i v1 = Shift<1>(v0);
__m256i v2 = Shift<2>(v0);
__m256i r = _mm256_add_epi16(v0, _mm256_add_epi16(v1, v2));
Print<short>(v0);
Print<short>(v1);
Print<short>(v2);
Print<short>(r);
}
Output:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0
2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 0
3 4 5 6 7 8 9 10 11 12 13 14 15 0 0 0
6 9 12 15 18 21 24 27 30 33 36 39 42 29 15 0
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With