期間2^128の変数__m128iが必要です。単調増加(カウンターのように)する必要はありませんが、各値を一度訪れてください。128ビットSSEカウンタ?
私が考えることができる最も単純な例は、実際には128ビットのカウンタですが、SSEで実装するのが難しいことがわかりました。よりシンプルで高速なソリューションはありますか?
期間2^128の変数__m128iが必要です。単調増加(カウンターのように)する必要はありませんが、各値を一度訪れてください。128ビットSSEカウンタ?
私が考えることができる最も単純な例は、実際には128ビットのカウンタですが、SSEで実装するのが難しいことがわかりました。よりシンプルで高速なソリューションはありますか?
単調カウンタです。私はあなたがそれを簡単に呼び出せるかどうか分からない。
ONE
とZERO
が常にレジスタにあると仮定すると、これは5つの命令にコンパイルする必要があります。 (VEXエンコードが使用されていない場合は7または8)
inline __m128i nextc(__m128i x){
const __m128i ONE = _mm_setr_epi32(1,0,0,0);
const __m128i ZERO = _mm_setzero_si128();
x = _mm_add_epi64(x,ONE);
__m128i t = _mm_cmpeq_epi64(x,ZERO);
t = _mm_and_si128(t,ONE);
t = _mm_unpacklo_epi64(ZERO,t);
x = _mm_add_epi64(x,t);
return x;
}
テストコード(MSVC):
int main() {
__m128i x = _mm_setr_epi32(0xfffffffa,0xffffffff,1,0);
int c = 0;
while (c++ < 10){
cout << x.m128i_u64[0] << " " << x.m128i_u64[1] << endl;
x = nextc(x);
}
return 0;
}
出力:
18446744073709551610 1
18446744073709551611 1
18446744073709551612 1
18446744073709551613 1
18446744073709551614 1
18446744073709551615 1
0 2
1 2
2 2
3 2
わずかに良好なバージョンによって示唆@ Norbert P.それは私の元の解決策に1命令を保存します。
inline __m128i nextc(__m128i x){
const __m128i ONE = _mm_setr_epi32(1,0,0,0);
const __m128i ZERO = _mm_setzero_si128();
x = _mm_add_epi64(x,ONE);
__m128i t = _mm_cmpeq_epi64(x,ZERO);
t = _mm_unpacklo_epi64(ZERO,t);
x = _mm_sub_epi64(x,t);
return x;
}
ありがとうございます、あなたのコードは私よりもはるかにクリーンです。私はカウンター以外の解決策があるかどうかを少し調べるつもりです。 – jk4736
これは、SSEを使用していないソリューションよりも実際に速い場合に問題になります。私は、2 64bit unsignedと1 branchの構造体を使用する明らかな解決策が、SSEオーバーヘッドを回避し、分岐が非常に予測可能であることを意味します。 – Voo
@Vooそれはおそらく、値がどんな形式で必要とされるかに依存するでしょう。汎用レジスタやメモリに必要な場合は、 'add + adc 'が最速になります。 SSEレジスタに必要な場合は、5種類のSSE-Int命令が抽出/挿入のどの種類よりも高速になる可能性があります。構造体/共用体を介してメモリに渡すと、別のワードサイズの同じメモリにアクセスしているため、ロード/ストアバッファが停止する可能性があります。 – Mysticial
KISSの原理を忘れないでください。
貼り付け、この(符号なし整数が故に、一度だけ、各値を訪問し、C標準で一巡するのに必要とされる):
addq $1, %rdi
adcq $0, %rsi
movq %rdi, %rax
movq %rsi, %rdx
ret
簡単:(x64の場合)this利回りに
__uint128_t inc(__uint128_t x) {
return x+1;
}
/十分に速い?あなたがいることをインライン化した場合、あなたはおそらくちょうどaddq
/adcq
で逃げることができるようになります(movq
sおよびret
はx64のABIによって必要とされている:あなたは関数をインライン場合、それらが必要とされていない)
inline void inc(unsigned long long *x, unsigned long long *y) {
if (!++*x) ++*y; // yay for obfuscation!
}
、しかし:あなたは以下を使用することができ、MSVCのsuckinessについてVOOさんのコメントに対処するために
私は上記の投稿。次に、が本当にに__m128iが必要な場合は、castを2つの半分にすることができます。
なぜ2^128値を訪問する必要がありますか?地球上のコンピュータはそれを行うことはできません。あなたは64ビットintを使用できませんか? – usr
ギガヘルツオーダーのクロック速度を持つプロセッサでは、64ビットカウンタが使い尽くされるまでに約584年間、1サイクルごとに1つの数値を消費することができます。 – Damon