2012-04-02 4 views
12

12832レジスタの左に論理シフトを行いますが、即値シフト値に制限され、ビットではなくバイトでシフトします。非即時シフト値のためのsse 128ビットシフト操作を探す

__m128iレジスタ内の値のセットを左にシフトするには_mm_sll_epi64または_mm_sll_epi32のような組み込み関数を使用できますが、これらは "オーバーフロー"ビットを持ちません。

  • _mm_sll_epi64
  • _mm_srr_epi64(ビットのために私が実行したい:低順にそれらを動かす)
  • シャッフルNビットだけシフトするために

    は、私のような何かができることを想像しますsrrの結果は

  • またはこれらをまとめたものです。

(おそらく64の相対Nのチェックも含む必要があります)。

良い方法がありますか?

+1

もっと良い方法はないと思います。私はこの質問の最近の複製への回答を書いた:http://stackoverflow.com/q/34478328/224132。コンパイル時定数の場合は、4つのinsn、またはcount> = 64の2つのinsnになります。変数countの場合、分岐し、整数からベクトルレジスタに64カウントします。データがすでに整数レジスタに入っている場合、 '__uint128_t'がその場合にはより良いでしょう。 –

答えて

4

あなたの理想的な解決策ではありませんが、8の倍数のビット数でSSEレジスタをローテーションまたはシフトする場合は、PSHUFB命令(および_mm_shuffle_epi8()組み込み関数)が役立ちます。 2番目のSSEレジスタを入力として受け取ります。レジスタの各バイトは、第1の入力レジスタ内のバイトをインデックスするために使用される値を保持する。

+4

私は、彼が細粒度を望んでいて、即時に制限されていないことを具体的に述べていると思います。 '_mm_shuffle_epi8()'はバイト単位であり、即値が必要です。 – Mysticial

+4

私は彼が細かい粒度を望んでいることを知っているので、私の答えの最初の節です。また、 '_mm_shuffle_epi8()'はすぐには必要ありません。 2番目の引数は '__m128i'の値です。 [こちらのドキュメントを参照してください](http://msdn.microsoft.com/en-us/library/bb531427.aspx) –

+1

この機能にはSSSE3のサポートが必要であることに注意してください。これは、古いマシンで実行したい場合には不十分かもしれません。 –

4

これは、ブログ投稿(私の)unusual C preprocessor usesの副題として浮上しました。 127個の異なるシフトオフセットに対して、ビットシフトのためのSSE2命令の4つの異なる最適シーケンスがあります。プリプロセッサは、129ウェイのswitch文に相当するシフト関数を構築することを妥当なものにします。ここで生コードを許してください。私はここに直接コードを投稿することには慣れていません。 ブログの記事で何が起こっているのかを確認してください。上記が、スワップ "SHL" とどこでもF [1256]マクロで "SHR" へ

#include <emmintrin.h> 

typedef __m128i XMM; 
#define xmbshl(x,n) _mm_slli_si128(x,n) // xm <<= 8*n -- BYTE shift left 
#define xmbshr(x,n) _mm_srli_si128(x,n) // xm >>= 8*n -- BYTE shift right 
#define xmshl64(x,n) _mm_slli_epi64(x,n) // xm.hi <<= n, xm.lo <<= n 
#define xmshr64(x,n) _mm_srli_epi64(x,n) // xm.hi >>= n, xm.lo >>= n 
#define xmand(a,b) _mm_and_si128(a,b) 
#define xmor(a,b) _mm_or_si128(a,b) 
#define xmxor(a,b) _mm_xor_si128(a,b) 
#define xmzero  _mm_setzero_si128() 

XMM xm_shl(XMM x, unsigned nbits) 
{ 
    // These macros generate (1,2,5,6) SSE2 instructions, respectively: 
    #define F1(n) case 8*(n): x = xmbshl(x, n); break; 
    #define F2(n) case n: x = xmshl64(xmbshl(x, (n)>>3), (n)&15); break; 
    #define F5(n) case n: x = xmor(xmshl64(x, n), xmshr64(xmbshl(x, 8), 64-(n))); break; 
    #define F6(n) case n: x = xmor(xmshl64(xmbshl(x, (n)>>3), (n)&15),\ 
            xmshr64(xmbshl(x, 8+((n)>>3)), 64-((n)&155))); break; 
    // These macros expand to 7 or 49 cases each: 
    #define DO_7(f,x) f((x)+1) f((x)+2) f((x)+3) f((x)+4) f((x)+5) f((x)+6) f((x)+7) 
    #define DO_7x7(f,y) DO_7(f,(y)+1*8) DO_7(f,(y)+2*8) DO_7(f,(y)+3*8) DO_7(f,(y)+4*8) \ 
             DO_7(f,(y)+5*8) DO_7(f,(y)+6*8) DO_7(f,(y)+7*8) 
    switch (nbits) { 
    case 0: break; 
    DO_7(F5, 0) // 1..7 
    DO_7(F1, 0) // 8,16,..56 
    DO_7(F1, 7) // 64,72,..120 
    DO_7x7(F6, 0) // 9..15 17..23 ... 57..63 i.e. [9..63]\[16,24,..,56] 
    DO_7x7(F2,56) // 65..71 73..79 ... 121..127 i.e. [65..127]\[64,72,..,120] 
    default: x = xmzero; 
    } 
    return x; 
} 

xm_shr量。 HTH。

+2

実際、上記のコードはシフト値の約半分では機能しません。 128ビット整数の標準シフト(gccは__uint128_tをサポート)に対してこれをテストしたところ、結果は大きく異なります。たとえば、すべてのシフトが120を超えると、すべてのビットがゼロになります。 – seba

+1

コンパイル時定数シフトのカウントでは、4つ以上の命令(またはAVXなしの5つの命令:余分な「movdqa」)は必要ありません。カウントが64未満の場合、バイトシフトは64bだけ残され、次にビットシフトは64カウントだけ実行されます。 'psllq xmm0、64'でキャリーを「OR」します。私は 'if'でそれを書いて、コンパイル時の定数としてhttp://goo.gl/O14GhIをうまくコンパイルします。 http://stackoverflow.com/a/34482688/224132 –

+0

を参照してください。コードを修正するには、すべて&15または&155の式を&7で置き換えてください。これは、このコードは非常に遅いです(分岐について知っていますか?)、Peter Cordesの提案ははるかに有望です。 –

関連する問題