Pytanie Praca z 8-bitowym przesunięciem w AVX2 z przesunięciem w zerach


Czy istnieje sposób na odbudowę? _mm_slli_si128 instrukcja w AVX2, aby przesunąć __mm256i rejestrować według x bajtów?

The _mm256_slli_si256 wydaje się po prostu wykonać dwa _mm_slli_si128 na [127: 0] i [255: 128].

Lewa zmiana powinna działać na __m256i lubię to:

[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, ..., 32] -> [2, 3, 4, 5, 6, 7, 8, 9, ..., 0]

Widziałem w wątek że można stworzyć przesunięcie przy pomocy _mm256_permutevar8x32_ps dla 32bit. Ale potrzebuję bardziej ogólnego rozwiązania, aby przesunąć o x bajtów. Czy ktoś już jest rozwiązaniem tego problemu?


11
2017-12-25 17:00


pochodzenie


Jeśli często musisz to robić, możesz pomyśleć o alternatywnym podejściu. AVX i nie tylko dzieli wektory na "ścieżki" 128-bitowe. Operacje cross-lane są bardzo drogie. Patrząc na dokumenty Agnera Fog, wygląda na to, że operacje na skrzyżowaniu są droższe niż źle ustawiony dostęp do pamięci. - Mysticial
bardzo dziękuję za odpowiedź. Sprawdzę jego dokumenty. Ale nie muszę używać rozkazu rozległego. Ale byłoby dobrze, gdybym mógł użyć poleceń SIMD. - martin s
Czy wartość przesunięcia jest stałą czasu kompilacji? - Iwillnotexist Idonotexist
tak, to jest czas kompilacji - martin s
@Mysticial: to kara opóźnienia, a nie przepustowość. VPERMD y,y,y, VPERMQ y,y,i, i VPERM2I128 y,y,y,i wszystko to 1uop, lat = 3c, przepustowość = 1 / cykl. (I wszyscy biegają na port5 tylko w Haswell.) Zgadzam się, jeśli możesz zorganizować rzeczy do pracy bez przekraczania pasów przez cały czas, to jest najlepsze. Ale jeśli twoje algo z natury przynosi korzyści, a dodatkowe opóźnienie nie jest zabójcze, może to być wygrana. - Peter Cordes


Odpowiedzi:


dobra, zaimplementowałem funkcję, która może przesunąć się w lewo do 16 bajtów.

template  <unsigned int N> __m256i _mm256_shift_left(__m256i a)
{
  __m256i mask =  _mm256_srli_si256(
          _mm256_permute2x128_si256(a, a, _MM_SHUFFLE(0,0,3,0))
          , 16-N);
  return _mm256_or_si256(_mm256_slli_si256(a,N),mask);
}

Przykład:

int main(int argc, char* argv[]) {
   __m256i reg =  _mm256_set_epi8(32,31,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,
                                  14,13,12,11,10,9,8,7,6,5,4,3,2,1);

   __m256i result = _mm256_shift_left<1>(reg);
   for(int i = 0; i < 32; i++)
     printf("%2d ",((unsigned char *)&result)[i]);
   printf("\n");
}

Wyjście to
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 0 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31

Edytować: Nowa wersja z nową instrukcją alignatora. Dzięki za podpowiedź @Evgney Kluev

template  <unsigned int N> __m256i _mm256_shift_left(__m256i a)
{
  __m256i mask = _mm256_permute2x128_si256(a, a, _MM_SHUFFLE(0,0,3,0) );
  return _mm256_alignr_epi8(a,mask,16-N);
}

9
2017-12-29 16:35



Możesz to zoptymalizować za pomocą _mm256_alignr_epi8 zamiast obu zmian i "lub". - Evgeny Kluev
Czy ktokolwiek wie, dlaczego VPALIGNRB (_mm256_alignr_epi8) nie znajduje się w tabelach instrukcji Agner Fog? Chcę poznać opóźnienie i przepustowość. - Z boson
@Zboson: Nie wiem, dlaczego Agner Fog to pominął. Ale ten zasób zgłasza zarówno opóźnienie, jak i przepustowość, aby być dokładnie jednym zegarem. - Evgeny Kluev
Stary komentarz, więc może tego brakowało 1,5 roku temu, ale PALIGNR v,v,i / v,v,v,i jest wymieniony dla Haswell w tablicach insynuacji Agnera Mgły. Wymienia on tylko insny z prefiksem V, jeśli nie ma wersji innej niż AVX. W przeciwnym razie jest tam mnożnik inny niż V i musisz spojrzeć na argumenty, aby zobaczyć, czy istnieje inny wpis, jeśli jest różnica między używaniem go na xmm i ymm args. - Peter Cordes
@BeeOnRope: heh, tak. Zaniedbałem jednak uwzględnienie opóźnień i przepustowości. No cóż, prawie wszystkie tasowania w tasie mają takie same opóźnienia i przepustowość na Haswell. - Peter Cordes