Chcę przetasować elementy wektora __m256i. Istnieje również wewnętrzne _mm256_shuffle_epi8, które robi coś podobnego, ale nie wykonuje shuffle w poprzecznym pasie.Pomieszaj elementy wektora __m256i
Jak mogę to zrobić, używając instrukcji AVX2?
Chcę przetasować elementy wektora __m256i. Istnieje również wewnętrzne _mm256_shuffle_epi8, które robi coś podobnego, ale nie wykonuje shuffle w poprzecznym pasie.Pomieszaj elementy wektora __m256i
Jak mogę to zrobić, używając instrukcji AVX2?
Jest na to sposób, aby naśladować tę operację, ale nie jest to bardzo piękny:
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)));
}
To nie jest piękne, ale działa w moim przypadku. Dziękuję Ci. –
Właściwie to jest dla mnie całkiem piękne. – BeeOnRope
pierwsze - wyjaśnienie - zwykle specyfikacja Intel wymaga, że wzór Shuffle być zdefiniowane w bitach 0-3 w każdy bajt dla każdego bajtu. Ponieważ starasz się wykonać tasowanie w linii poprzecznej, twój tasujący wzór wykorzystuje również bit 4, do reprezentowania bajtów znajdujących się w indeksie położenia powyżej 15 w rejestrze YMM.
Założenia: to, co chcesz przetasować, to w YMM0, a wzór jest w YMM1.
Kod jest jak poniżej:
mask_pattern_0 db 0FH
mask_pattern_1 db 10H
vpbroadcastb ymm2,byte ptr mask_pattern_0 ; Load the mask
vmovdqu ymm5,ymm2
vpsubb ymm3,ymm2,ymm1 ; YMM3 has neg for all those exceeding 15 in original shuffle pattern
vpsignb ymm4,ymm1,ymm3 ; YMM4 replicates shuffle pattern with a neg at all those that are above 15 in the original shuffle pattern
vperm2i128 ymm2,ymm0,ymm0,00010001b ; Save the upper 128 bits of the target YMM0 to YMM2 in both upper and lower 128 bits
vperm2i128 ymm0,ymm0,ymm0,00100000b ; This replicates the lower 128 bits of YMM0 to upper 128 bits of YMM0
vpshufb ymm0,ymm0,ymm4 ; This places all those with index below 16 to appropriate place, and sets a zero to other bytes
;We now process the entries in shuffle pattern with index above 15
vpsubb ymm3,ymm1,ymm5 ; Now all those above 15 have a positive value
vpsignb ymm4,ymm1,ymm3 ; YMM4 has negatives for all those below 15 in original shuffle pattern YMM1
vpbroadcastb ymm5,byte ptr mask_pattern_1 ; Load the mask value 10H
vpsubb ymm4,ymm4,ymm5
vpshufb ymm2,ymm2,ymm4 ; Save the shuffle in YMM2
vpaddb ymm0,ymm0,ymm2
Zapewnia również, że wzór jest zawarty w YMM1 nietknięty - co prawda z instrukcją VPSHUFB.
Zaufanie to pomaga ...
Konkretny losowego lub jakikolwiek losowe jak gdybyś miał przekrój pasa 'pshufb'? – harold
Używam _mm_shuffle_epi8 do optymalizacji kodu SSE. Ale wspólne używanie instrukcji AVX i SSE nie jest dobrym pomysłem, prawda? –
Jest w porządku, o ile instrukcje SSE mają kodowanie VEX. – harold