2012-05-17 25 views
6

short(またはint)の出力先配列に追加する必要がある非常に長いバイト配列があります。 このようなSSE命令は存在しますか?またはそれらのセット?SSE命令:Byte + Short

答えて

6

8ビット値の各ベクトルを16ビット値の2つのベクトルにアンパックしてそれらを加算する必要があります。

__m128i v = _mm_set_epi8(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); 
__m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0)); // vl = { 7, 6, 5, 4, 3, 2, 1, 0 } 
__m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0)); // vh = { 15, 14, 13, 12, 11, 10, 9, 8 } 

vは16×8ビット値のベクトルとvlであり、vhは8×16ビット値の二アンパックベクトルです。

私は8ビット値が符号なしであると仮定しているので、16ビットにアンパックすると上位バイトは0(つまり符号拡張なし)に設定されます。

これらのベクトルの多くを合計して32ビットの結果を得たい場合は、_mm_madd_epi16と1を使用すると便利です。

__m128i vsuml = _mm_set1_epi32(0); 
__m128i vsumh = _mm_set1_epi32(0); 
__m128i vsum; 
int sum; 

for (int i = 0; i < N; i += 16) 
{ 
    __m128i v = _mm_load_si128(&x[i]); 
    __m128i vl = _mm_unpacklo_epi8(v, _mm_set1_epi8(0)); 
    __m128i vh = _mm_unpackhi_epi8(v, _mm_set1_epi8(0)); 
    vsuml = _mm_add_epi32(vsuml, _mm_madd_epi16(vl, _mm_set1_epi16(1))); 
    vsumh = _mm_add_epi32(vsumh, _mm_madd_epi16(vh, _mm_set1_epi16(1))); 
} 
// do horizontal sum of 4 partial sums and store in scalar int 
vsum = _mm_add_epi32(vsuml, vsumh); 
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 8)); 
vsum = _mm_add_epi32(vsum, _mm_srli_si128(vsum, 4)); 
sum = _mm_cvtsi128_si32(vsum); 
+1

私の知らないことがありますが、これは間違いないと思いますか?このvsum = _mm_madd_epi16(vh、_mm_set1_epi16(1));以前のvsumの値が消去されます。 – Alexandros

+0

@Alexandros:あなたは正しいと思います。私はこの答えを書いたときに急いでいたに違いないと思います。すぐにコードを修正しますが、私は旅行しています。プレゼント。 –

+1

ありがとうポール、急いではありません。あなたは過去に私をたくさん助けてくれました。いつでも可能な限り修正してください。良い旅を!! – Alexandros

0

ゼロ拡張ではなく、バイトベクトルを符号拡張する必要がある場合は、pmovsxbw (_mm_cvtepi8_epi16)を使用します。 unpack hi/lo命令とは異なり、srcレジスタの下半分/四分の一/ 8分の1からpmovsxしかできません。

intrinsicsがこれを本当に不器用にしても、メモリから直接pmovsxを実行できます。シャッフルスループットはほとんどのCPUの負荷スループットよりも制限されているので、1ロード+ 3シャッフルよりも2ロード+ pmovsxを実行する方が望ましいでしょう。