Как сделать mm256 maskstore epi8 () на C/C++?
проблема
то, что я пытаюсь сделать, это, если у меня есть вектор 27 (не 32!) int8_t
:
x = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26}
я хочу сначала циклически сдвинуть его вправо на n (не является константой), например, если n=1:
x2 = {26,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25}
тогда этот вектор используется для выполнения некоторых очень сложных вычислений, но для простоты предположим, что следующий шаг-просто циклический-сдвинуть его влево на n и сохранить его в память. Поэтому у меня должен быть новый вектор 27 int8_t
:
y = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26}
таким образом, есть тысячи таких векторов, и производительность здесь очень важна. Процессор, который мы используем, поддерживает AVX2, поэтому мы хотим использовать его для ускорения работы.
мое текущее решение
и x2
, Я использую два _mm256_loadu_si256()
С _mm256_blendv_epi8()
:
int8_t x[31+27+31];
for(int i=0; i<27; i++){
x[31+i] = i;
}
__m256i mask = _mm256_set_epi32 (0x0, 0x00800000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0);
__m256i x_second_part = _mm256_loadu_si256((__m256i*)(x+31+1)); //{1,2,...,26}
__m256i x_first_part = _mm256_loadu_si256((__m256i*)(x+31-26)); //{0}
__m256i x2 = _mm256_blendv_epi8(x_second_part, x_first_part, mask); //{1,2,...,26, 0}
int8_t y[31+27+31];
_mm256_storeu_si256((__m256i*)(y+31-26), x2);
_mm256_storeu_si256((__m256i*)(y+31+1), x2);
почему x
и y
объявляются в размере [31+27+31]
заключается в том, что в это дело _mm256_loadu_si256()
и _mm256_storeu_si256()
не вызовет segfault.
и я могу получить значение y
by:
for(int i=0; i<27; i++){
cout << (int)y[31+i] << ' ';
}
новая задача
к сожалению, все векторы должны быть непрерывными в памяти, например, если есть два вектора, которые должны быть обработаны:
x = {[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26];
[27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53]};
тогда я не могу просто использовать _mm256_storeu_si256()
поставить значение y
назад в память, потому что когда значение второго вектора записывается в память, оно будет перезаписать некоторые значения первого вектора:
int8_t x[31+27+27+31];
int8_t y[31+27+27+31];
for(int i=0; i<27*2; i++){
x[31+i] = i;
}
for(int i=0; i<2; i++){
__m256i mask = _mm256_set_epi32 (0x0, 0x00800000, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0);
__m256i x_second_part = _mm256_loadu_si256((__m256i*)(x+31+27*i+1)); //{1,2,...,26}
__m256i x_first_part = _mm256_loadu_si256((__m256i*)(x+31+27*i-26)); //{0}
__m256i x2 = _mm256_blendv_epi8(x_second_part, x_first_part, mask); //{1,2,...,26, 0}
_mm256_storeu_si256((__m256i*)(y+31+27*i-26), x2);
_mm256_storeu_si256((__m256i*)(y+31+27*i+1), x2);
}
for(int i=0; i<27; i++){
cout << (int)y[31+i] << ' ';
}cout << endl;
for(int i=0; i<27; i++){
cout << (int)y[31+27+i] << ' ';
}cout << endl;
выводит
0 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
вместо
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
поэтому я думал об использовании maskstore. Но в Intel Встроенное Руководство я не смог найти _mm256_maskstore_epi8
. Это возвращает меня к теме:
как сделать _mm256_maskstore_epi8 () в C/C++?
2 ответов
существует еще одна реализация циклического сдвига внутри 27-байтового вектора с использованием AVX2:
#include <iostream>
#include <immintrin.h>
const __m256i K0 = _mm256_setr_epi8(
0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70,
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0);
const __m256i K1 = _mm256_setr_epi8(
0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0,
0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70, 0x70);
inline const __m256i Shuffle(const __m256i & value, const __m256i & shuffle)
{
return _mm256_or_si256(_mm256_shuffle_epi8(value, _mm256_add_epi8(shuffle, K0)),
_mm256_shuffle_epi8(_mm256_permute4x64_epi64(value, 0x4E), _mm256_add_epi8(shuffle, K1)));
}
__m256i shuffles[27];
void Init()
{
uint8_t * p = (uint8_t *)shuffles;
for (int s = 0; s < 27; ++s)
for (int i = 0; i < 32; ++i)
p[s*32 + i] = i < 27 ? (27 + i - s)%27 : i;
}
void CyclicShift27(const uint8_t * src, size_t shift, uint8_t * dst)
{
_mm256_storeu_si256((__m256i*)dst, Shuffle(_mm256_loadu_si256((__m256i*)src), shuffles[shift]));
}
int main()
{
Init();
uint8_t src[32] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31 }, dst[32];
for (int j = 0; j < 27; ++j)
{
CyclicShift27(src, j, dst);
std::cout << "\t";
for (int i = 0; i < 32; i++)
std::cout << (int)dst[i] << ' ';
std::cout << std::endl;
}
return 0;
}
выход:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 27 28 29 30 31
25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 27 28 29 30 31
24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 27 28 29 30 31
23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 27 28 29 30 31
22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 27 28 29 30 31
21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 27 28 29 30 31
20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 27 28 29 30 31
19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 27 28 29 30 31
18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 27 28 29 30 31
17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 27 28 29 30 31
16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 27 28 29 30 31
15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 27 28 29 30 31
14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 27 28 29 30 31
13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 27 28 29 30 31
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 27 28 29 30 31
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 27 28 29 30 31
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 27 28 29 30 31
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 27 28 29 30 31
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 27 28 29 30 31
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 27 28 29 30 31
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 27 28 29 30 31
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 27 28 29 30 31
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 27 28 29 30 31
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 27 28 29 30 31
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 27 28 29 30 31
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 27 28 29 30 31
выглядит более простым, чем мой предыдущий ответ.
Я сделал реализацию циклического сдвига внутри 27-байтового вектора с использованием SSSE3:
#include <iostream>
#include <tmmintrin.h>
union Shuffle
{
uint8_t s[64];
__m128i v[4];
};
Shuffle shuffles[27];
int Shift(int value)
{
return (value >= 0 && value < 16) ? value : -1;
}
void Init()
{
for (int s = 0; s < 27; ++s)
{
for (int i = 0; i < 16; ++i)
{
shuffles[s].s[0 + i] = s < 16 ? Shift(i - s) : Shift(i - s + 27);
shuffles[s].s[16 + i] = Shift(16 + i - s);
shuffles[s].s[32 + i] = Shift(11 + i - s);
shuffles[s].s[48 + i] = s < 11 ? Shift(i - s) : Shift(i - s + 27);
}
}
}
void CyclicShift27(const uint8_t * src, size_t shift, uint8_t * dst)
{
__m128i srcLo = _mm_loadu_si128((__m128i*)(src + 0));
__m128i srcHi = _mm_loadu_si128((__m128i*)(src + 11));
__m128i dstLo = _mm_or_si128(_mm_shuffle_epi8(srcLo, shuffles[shift].v[0]), _mm_shuffle_epi8(srcHi, shuffles[shift].v[1]));
__m128i dstHi = _mm_or_si128(_mm_shuffle_epi8(srcLo, shuffles[shift].v[2]), _mm_shuffle_epi8(srcHi, shuffles[shift].v[3]));
_mm_storeu_si128((__m128i*)(dst + 0), dstLo);
_mm_storeu_si128((__m128i*)(dst + 11), dstHi);
}
int main()
{
Init();
uint8_t src[27] = { 0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26 }, dst[27];
for (int j = 0; j < 27; ++j)
{
CyclicShift27(src, j, dst);
for (int i = 0; i < 27; i++)
std::cout << (int)dst[i] << ' ';
std::cout << std::endl;
}
return 0;
}
это выход:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14
14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12 13
13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11 12
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10 11
11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9 10
10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8 9
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7 8
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6 7
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5 6
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4 5
5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3 4
4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2 3
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1 2
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 0
Я надеюсь, что это будет полезно.