我需要一個具有周期2^128的__m128i變量的函數。它不需要單調增加(就像一個計數器),而是每訪問一次值。128位SSE計數器?
我能想到的最簡單的例子實際上是一個128位的計數器,但我發現很難在SSE中實現。有沒有更簡單/更快的解決方案?
我需要一個具有周期2^128的__m128i變量的函數。它不需要單調增加(就像一個計數器),而是每訪問一次值。128位SSE計數器?
我能想到的最簡單的例子實際上是一個128位的計數器,但我發現很難在SSE中實現。有沒有更簡單/更快的解決方案?
這是一個單調的計數器。我不確定你是否可以簡單地調用它。
假設ONE
和ZERO
總是在寄存器中,那麼這應該編譯成5條指令。 (7或8,如果不使用VEX編碼)
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 2012-02-19 18:47:58
問題是,如果這真的比不使用任何SSE的解決方案更快。我的意思是使用2個64位無符號結構和1個分支的明顯解決方案將避免可能的SSE開銷,並且分支將是非常可預測的。 – Voo 2012-02-19 23:37:32
@Voo它可能取決於需要什麼樣的價值形式。如果在通用寄存器或內存中需要它,那麼'add + adc'將會是最快的。如果在SSE寄存器中需要它,那麼5個SSE-Int指令可能會比任何提取/插入更快。由於您使用不同的字大小訪問相同的內存,因此通過結構/聯合將其傳遞到內存中可能會使加載/存儲緩衝區停頓。 – Mysticial 2012-02-19 23:44:20
永遠不要忘記KISS原則。
粘貼(需要無符號整數C標準環繞,因此訪問每個值僅一次)這樣的:(針對x64)
__uint128_t inc(__uint128_t x) {
return x+1;
}
到this收率:
addq $1, %rdi
adcq $0, %rsi
movq %rdi, %rax
movq %rsi, %rdx
ret
容易/夠快?如果內聯,你可能能夠與剛剛addq
/adcq
脫身(在movq
S和由64位ABI需要ret
:如果內聯函數,不需要他們)
爲了解決VOO的評論關於MSVC的suckiness,您可以使用以下命令:
inline void inc(unsigned long long *x, unsigned long long *y) {
if (!++*x) ++*y; // yay for obfuscation!
}
我沒有MSVC安裝在附近,所以我不能測試,但它應該類似產量東西我上面發佈的內容。那麼,如果你真的需要一個__m128i,你應該可以把cast兩半。
爲什麼你需要訪問2^128值?地球上的任何一臺計算機都無法做到這一點。你不能使用64位int嗎? – usr 2012-10-31 12:03:33
在時鐘速度爲千兆赫茲的處理器上達成一致,在64位計數器耗盡之前,您可以在大約584年的每個週期內消耗一個數字。 – Damon 2014-04-02 11:48:53