2012-11-20 15 views
6

ile SSE karıştırılmış 32 bit değeri ayıklamak Verimli bir şekilde 128 bitlik bir kayıttan 4 bayt çıkarmaya çalışıyorum. Sorun, her değerin bir sperate 32bit {120,0,0,0,55,0,0,0,42,0,0,0,120,0,0,0} olmasıdır. Ben 128 bit 32 bit dönüştürmek istiyorum form {120,55,42,120}.Yalnızca SSE2

"ham" kod aşağıdaki gibi görünür:

__m128i byte_result_vec={120,0,0,0,55,0,0,0,42,0,0,0,120,0,0,0}; 
unsigned char * byte_result_array=(unsigned char*)&byte_result_vec; 
result_array[x]=byte_result_array[0]; 
result_array[x+1]=byte_result_array[4]; 
result_array[x+2]=byte_result_array[8]; 
result_array[x+3]=byte_result_array[12]; 

Benim SSSE3 kodudur:

unsigned int * byte_result_array=...; 
__m128i byte_result_vec={120,0,0,0,55,0,0,0,42,0,0,0,120,0,0,0}; 
const __m128i eight_bit_shuffle_mask=_mm_set_epi8(1,1,1,1,1,1,1,1,1,1,1,1,0,4,8,12);  
byte_result_vec=_mm_shuffle_epi8(byte_result_vec,eight_bit_shuffle_mask); 
unsigned int * byte_result_array=(unsigned int*)&byte_result_vec; 
result_array[x]=byte_result_array[0]; 

Ben SSE2 ile bu verimli yapabiliriz nasıl. SSSE3 veya SSE4 ile daha iyi bir sürümü var mı?

cevap

9

Bunun için bazı çözümler ve ters işlem için a previous answer of mine'a bakabilirsiniz. SSE2 Özellikle

ilk imzalanmış 16 bit tamsayılar içine 32 bit tamsayılar paketleme ve doyurarak yapabilirsiniz:

byte_result_vec = _mm_packs_epi32(byte_result_vec, byte_result_vec); 

Sonra işaretsiz 8 bit değerlerine olanlar 16 bit değerlerini paketi sonra nihayet kayıt alt 32-bit bizim değerleri alabilir

byte_result_vec = _mm_packus_epi16(byte_result_vec, byte_result_vec); 

:

int int_result = _mm_cvtsi128_si32(byte_result_vec); 
unsigned char* byte_result_array = (unsigned char*)&int_result; 
result_array[x] = byte_result_array[0]; 
result_array[x+1] = byte_result_array[1]; 
result_array[x+2] = byte_result_array[2]; 
result_array[x+3] = byte_result_array[3]; 
işaretsiz doygunluğu kullanarak

DÜZENLEME: Yukarıdakiler, 8 bitlik sözcüklerin başlangıçta ilgili 32 bitlik sözcüklerin düşük baytlarında olduğunu ve geri kalanı da doyurma paketleme işlemi sırasında kelepçeleneceği için 0 s ile doldurulduğunu varsayar. Böylece işlemler aşağıdaki gibidir: uninterresting bayt başlangıçta 0 s ile dolu değilse

   byte 15        0 
        0 0 0 D 0 0 0 C 0 0 0 B 0 0 0 A 

_mm_packs_epi32 -> 0 D 0 C 0 B 0 A 0 D 0 C 0 B 0 A 

_mm_packus_epi16 -> D C B A D C B A D C B A D C B A 
               ^^^^^^^ 

_mm_cvtsi128_si32 -> int DCBA, laid out in x86 memory as bytes A B C D 

-> reinterpreted as unsigned char array { A, B, C, D } 

, önceden onları uzak maskelemek zorunda:

byte_result_vec = _mm_and_si128(byte_result_vec, _mm_set1_epi32(0x000000FF)); 

Veya interresting bayt başlangıçta ise aslında { D, C, B, A } istiyorsanız compl almayan (

byte_result_vec = _mm_srli_epi32(byte_result_vec, 24); 

Veya: yüksek bayt, önceden düşük bayt içine kaydırmaya sahip Sorunuzdan bana net olarak), iyi, o zaman bu sadece atamalarda dizi indeksini değiştirmeye ya da (ya da alternatif olarak ilk SSE kaydında bir 32-bit shuffle (_mm_shuffle_epi32) perfoming) tutar.

+0

Bu mükemmel bir cevaptır. İki kez nasıl kazanabilirim? :) bu bana çok yardımcı oldu. SSE4 ile daha iyi bir yol biliyor musunuz? –

+0

@martins: SSSE3 ve üstü ile, sadece bir PSHUFB (mevcut kodunuzun derlemesi gereken). –

+0

@martins SSE> 2'de bu kadar iyi eğitim almıyorum, belki de bakmaya çalışacağım. –