2017-02-22 62 views
1

Рассматривают У меня есть массив SSE с 16 битными данными:Преобразовать 8 16 бит SSE регистр для 8bit данных

{1,2,3,4,5,6,7,8}

Теперь мне нужно, чтобы преобразовать этот массив SSE в 8 бит данных, сохраняя только младший байт 16-разрядных данных в первые 8 байт, как:

{1,2,3,4,5,6,7,8,0,0,0,0,0,0,0,0}.

есть ли инструкция SSE для выполнения этой операции?

+3

'pshufb' может сделать это, фактические инструкции пак насыщают – harold

+0

См https://stackoverflow.com/questions/46468026/fast-copy-every-second- byte-to-new-memory-area для выполнения этого над массивом, вместо того, чтобы упаковывать один единственный вектор и оставляя нули в высоком 64b. –

ответ

3

Как указано в комментариях выше, вы можете сделать это довольно легко с помощью pshufb aka _mm_shuffle_epi8, например.

#include <stdio.h> 
#include <tmmintrin.h> 

static __m128i pack_16_to_8(const __m128i v) 
{ 
    const __m128i vperm = _mm_setr_epi8(0, 2, 4, 6, 8, 10, 12, 14, -1, -1, -1, -1, -1, -1, -1, -1); 

    return _mm_shuffle_epi8(v, vperm); 
} 

int main(void) 
{ 
    const __m128i v = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8); 

    printf("%vhd -> %vd\n", v, pack_16_to_8(v)); 
    return 0; 
} 

компилировать и запускать:

$ gcc -Wall -mssse3 pack_16_to_8.c && ./a.out 

1 2 3 4 5 6 7 8 -> 1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0 
1

Дополнение ответить Павла К:

расширение SSE2 содержит команды PACKSSWB(_mm_packs_epi16) и PACKUSWB (_mm_packus_epi16). Эти команды специально разработаны для преобразования 16-битного вектора в 8-битный вектор. Они выполняют насыщенность 16-разрядных (подписанных и неподписанных) значений, если эти значения превышают 8-разрядное целое число без знака (0..255).

#include <iostream> 
#include <emmintrin.h> 

template<class T> inline void Print(const __m128i & v) 
{ 
    T b[sizeof(v)/sizeof(T)]; 
    _mm_storeu_si128((__m128i*)b, v); 
    for (int i = 0; i < sizeof(v)/sizeof(T); i++) 
     std::cout << int(b[i]) << " "; 
    std::cout << std::endl; 
} 

int main() 
{ 
    __m128i v16 = _mm_setr_epi16(1, 2, 3, 4, 5, 6, 7, 8); 

    Print<uint8_t>(_mm_packs_epi16(v16, _mm_setzero_si128())); 
    Print<uint8_t>(_mm_packus_epi16(v16, _mm_setzero_si128())); 

    return 0; 
} 

Выход:

1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0 
1 2 3 4 5 6 7 8 0 0 0 0 0 0 0 0