6

効率的な方法で 128 ビット レジスタから 4 バイトを抽出しようとしています。問題は、各値が別々の 32bit にあること{120,0,0,0,55,0,0,0,42,0,0,0,120,0,0,0}です。128ビットを32ビットに変換したい{120,55,42,120}.

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

__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 のより良いバージョンはありますか?

4

1 に答える 1

10

これと逆の操作に対するいくつかの解決策については、私の以前の回答を参照してください。

特に SSE2 では、最初に 32 ビット整数を符号付き 16 ビット整数にパックし、飽和させることでそれを行うことができます。

byte_result_vec = _mm_packs_epi32(byte_result_vec, byte_result_vec);

次に、符号なし飽和を使用して、これらの 16 ビット値を符号なし 8 ビット値にパックします。

byte_result_vec = _mm_packus_epi16(byte_result_vec, byte_result_vec);

その後、最終的にレジスタの下位 32 ビットから値を取得できます。

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 ビット ワードの下位バイトにあり、残りは0s で満たされていると想定しています。そうしないと、飽和パッキング プロセス中にクランプされるためです。したがって、操作は次のとおりです。

             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 }

0興味のないバイトが最初に sで満たされていない場合は、事前にそれらをマスクする必要があります。

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

または、関心のあるバイトが最初に上位バイトにある場合は、事前にそれらを下位バイトにシフトする必要があります。

byte_result_vec = _mm_srli_epi32(byte_result_vec, 24);

または、実際に必要な場合{ D, C, B, A }(質問からは完全に明確ではありません)、これは割り当てで配列インデックスを切り替えるだけです (または、_mm_shuffle_epi32事前に初期 SSE レジスタで 32 ビット シャッフル () を実行することになります)。 )。

于 2012-11-20T14:14:38.627 に答える