2012-11-20 6 views
6

効率的に128ビットレジスタから4バイトを抽出しようとしています。問題は、各値が32ビットの32ビット{120,0,0,0,55,0,0,0,42,0,0,0,120,0,0,0}にあることです。私は128ビットを32ビットに変換したいのですが、それは{120,55,42,120}という形式です。SSEを抽出するSSE2のみで32ビット値をシャッフル

"生" のコードは次のようになります。

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

マイSSSE3コードを次のとおりです。

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

は、どのように私はSSE2を効率的にこれを行うことができます。 SSSE3またはSSE4のより良いバージョンがありますか?

答えて

9

これと逆の操作については、a previous answer of mineをご覧ください。 SSE2で特に

最初に符号付き16ビット整数に32ビット整数を梱包し、飽和させることによってそれを行うことができます。

byte_result_vec = _mm_packs_epi32(byte_result_vec, byte_result_vec); 

はその後、我々は、符号なし8ビットの値にこれらの16ビット値をパック我々は最終的にレジスタの下位32ビットから私たちの値を取ることができ

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]; 
符号なし飽和を使用して

編集:上記の説明では、8ビットワードは最初はそれぞれ32ビットワードの下位バイトにあり、残りは0で埋められていると仮定します。そうでないと飽和しているパッキングプロセス中にクランプされます。 interrestingバイトで最初にある場合

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

または:

   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 } 

uninterrestingバイトが最初に0秒で満たされていない場合は、事前にそれらを離れてマスクすることがあります。そのための操作は次のとおりですあなたが実際にCOMPLされていない({ D, C, B, A }をしたい場合は、

byte_result_vec = _mm_srli_epi32(byte_result_vec, 24); 

または高バイトは、あなたが事前に低いバイトにそれらをシフトする必要がありますあなたの質問からわかります)、これは割り当ての配列インデックスを切り替えるだけです(または最初のSSEレジスタの32ビットシャッフル(_mm_shuffle_epi32)を交互に実行することになります)。

+0

これは完璧な答えです。どうすれば2回upvoteできますか? :)これは私をたくさん助けました。 SSE4でより良い方法を知っていますか? –

+0

@martins:SSSE3以降では、PSHUFB(既存のコードをコンパイルする必要がある)だけが必要です。 –

+0

@martins私はSSE> 2に精通していませんが、おそらく私はそれを調べようとします。 –

関連する問題