2016-12-26 9 views
6

Wdrażam konwersje między typami SSE i odkryłem, że implementacja konwersji int8-> int64 dla celów pre-SSE4.1 jest uciążliwa.Jak skutecznie wykonać konwersję int8/int64 z SSE?

Prosta implementacja będzie:

inline __m128i convert_i8_i64(__m128i a) 
{ 
#ifdef __SSE4_1__ 
    return _mm_cvtepi8_epi64(a); 
#else 
    a = _mm_unpacklo_epi8(a, a); 
    a = _mm_unpacklo_epi16(a, a); 
    a = _mm_unpacklo_epi32(a, a); 
    return _mm_srai_epi64(a, 56); // missing instrinsic! 
#endif 
} 

Ale ponieważ _mm_srai_epi64 nie istnieje aż AVX-512, istnieją dwie możliwości w tym momencie:

  • wykonawcze _mm_srai_epi64 lub
  • wdrażanie convert_i8_i64 w inny sposób.

Nie jestem pewien, który z nich byłby najbardziej efektywnym rozwiązaniem. Dowolny pomysł?

Odpowiedz

4

Własności rozpakowywania używane są tutaj w zabawny sposób. "Duplikują" dane, zamiast dodawać rozszerzenia znaków, jak można się było spodziewać. Na przykład, przed pierwszym iteracji masz w rejestrze następujące

x x x x x x x x x x x x x x a b 

Jeśli konwertować a i b do 16 bitów, należy uzyskać w ten sposób:

x x x x x x x x x x x x A a B b 

Tutaj A i B są steru- rozszerzenia a i b, czyli oba z nich mają wartość 0 lub -1.

Zamiast tego kodu daje

x x x x x x x x x x x x a a b b 

A potem przekonwertować go do prawidłowego wyniku poprzez przesunięcie w prawo.

Jednak nie jesteś zobowiązany do użycia tego samego argumentu dwukrotnie w "rozpakowywaniu" nieinwazyjności. Można uzyskać pożądany efekt, jeżeli ty "rozpakowanych" dwa następujące rejestry:

x x x x x x x x x x x x x x a b 
x x x x x x x x x x x x x x A B 

Czyli:

a = _mm_unpacklo_epi8(a, _mm_srai_epi8(a, 8)); 

(jeśli _mm_srai_epi8 nieodłącznym rzeczywiście istniała)


Można zastosuj tę samą ideę do ostatniego etapu konwersji. Chcesz "rozpakować" dwa następujące rejestry:

x x x x x x x x A A A a B B B b 
x x x x x x x x A A A A B B B B 

aby je prawym przesunąć dane 32-bitowe:

_mm_srai_epi32(a, 24) 
_mm_srai_epi32(a, 32) 

Więc ostatni "rozpakować" jest

_mm_unpacklo_epi32(_mm_srai_epi32(a, 24), _mm_srai_epi32(a, 32)); 
2

W przypadku SSSE3 można użyć numeru pshufb, aby uniknąć większości rozpakowań.Korzystanie Anatolij za a/A notacji:

;; input in xmm0    ;; x x x x x x x x | x x x x x x a b 
pshufb xmm0, [low_to_upper] ;; a 0 0 0 0 0 0 0 | b 0 0 0 0 0 0 0 
psrad xmm0, 24    ;; A A A a 0 0 0 0 | B B B b 0 0 0 0 
pshufb xmm0, [bcast_signextend]; A A A A A A A a | B B B B B B B b 

Bez ssse3, myślę, że może być w stanie coś zrobić z PSHUFLW, PSHUFD, a może POR zamiast niektórych etapów PUNPCK. Ale nic, o czym myślałem, nie jest tak naprawdę lepsze od pakietów, chyba że używasz procesora Core2 lub innego wolno działającego procesora, gdzie pshuflw jest szybszy niż punpcklbw.