2016-12-26 10 views
6

Я реализую преобразования между типами SSE, и я обнаружил, что внедрение расширения int8-> int64 для целей до SSE4.1 является громоздким.Как эффективно выполнить преобразование int8/int64 с помощью SSE?

Непосредственное осуществление будет:

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 
} 

Но поскольку _mm_srai_epi64 не существует до тех пор, AVX-512, не два варианта на данный момент:

  • реализующие _mm_srai_epi64 или
  • реализуя convert_i8_i64 по-другому.

Я не уверен, какой из них был бы наиболее эффективным решением. Есть идеи?

ответ

4

Исключительные функции распаковки используются здесь смешным способом. Они «дублируют» данные, вместо добавления расширения знака, как и следовало ожидать. Например, перед первой итерацией у вас в реестре следующие

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

Если преобразовать a и b до 16 бит, вы должны получить это:

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

Здесь A и B являются Sign- расширениями a и b, то есть оба они равны 0 или -1.

Вместо этого, ваш код дает

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

А затем конвертировать его в нужный результат путем сдвига вправо.

Однако вы не должны использовать один и тот же операнд дважды в свойствах «распаковать». Вы можете получить желаемый результат, если вы "распакованные" следующие два регистра:

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 

То есть:

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

(если _mm_srai_epi8 присущий действительно существовала)


Вы можете примените ту же идею к последней стадии вашего преобразования. Вы хотите, чтобы "распаковать" следующие два регистра:

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 

Чтобы получить их, сдвиг вправо на 32-битовые данные:

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

Так что последний "распаковывать" является

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

С SSSE3 вы можете использовать pshufb, чтобы избежать большинства распаковки.Использование для Anatoly a/A обозначения:

;; 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 

Без SSSE3, я думаю, вы могли бы быть в состоянии сделать что-то с PSHUFLW, PSHUFD, и, возможно, POR вместо некоторых из шагов PUNPCK. Но ничего, о чем я думал, на самом деле лучше, чем распаковки, если вы не используете Core2 или другой процессор с медленным перемешиванием, где pshuflw быстрее, чем punpcklbw.