2017-04-30 44 views
8

除了測試單個寄存器是否全零之外,您還可以使用SSE4.1 ptest做什麼?可以使用PTEST來測試兩個寄存器是否都爲零或其他條件?

您可以使用SF和CF的組合來測試關於兩個未知輸入寄存器的任何有用信息嗎?

什麼是PTEST的好處?你可能會認爲這將是很好的檢查結果爲填充比較(如PCMPEQD或CMPPS),但至少在英特爾CPU,it costs more uops to compare-and-branch using PTEST + JCC than with PMOVMSK(B/PS/PD) + macro-fused CMP+JCC.

參見Checking if TWO SSE registers are not both zero without destroying them

回答

5

沒有,除非我失去了巧妙的是,有兩個未知寄存器的ptest通常對於檢查它們兩個的某些屬性是沒有用的。 (除了明顯的東西,你已經想要一個按位與AND,就像兩個位圖之間的交集)。

要測試兩個寄存器都爲零,或者將它們放在一起,並對它們自己進行PTEST測試。


ptest xmm0, xmm1產生兩個結果:

  • ZF =是xmm0 & xmm1全零?
  • CF =是(~xmm0) & xmm1全零?

如果第二個矢量是全零,則標誌完全不依賴於第一個矢量中的位。

將「is-all-zero」檢查視爲AND和ANDNOT結果的NOT(bitwise horizontal-OR())可能很有用。但可能不會,因爲這對於我的大腦輕鬆地進行思考來說太困難了。垂直AND和水平OR的順序可能會使得更容易理解爲什麼PTEST不會告訴你很多關於兩個未知寄存器的組合,就像整數TEST指令一樣。

下面是一個2位ptest a,mask的真值表。希望這有助於考慮混合零和128b輸入的混合。

請注意,CF(a,mask) == ZF(~a,mask)

a mask  ZF CF 
00 00  1  1 
01 00  1  1 
10 00  1  1 
11 00  1  1 

00 01  1  0 
01 01  0  1 
10 01  1  0 
11 01  0  1 

00 10  1  0 
01 10  1  0 
10 10  0  1 
11 10  0  1 

00 11  1  0 
01 11  0  0 
10 11  0  0 
11 11  0  1 

Intel's intrinsics guide lists 2 interesting intrinsics for it。注意args的命名爲:amask是他們告訴你關於由已知的AND掩碼選擇的部分a的線索。

  • _mm_test_mix_ones_zeros (__m128i a, __m128i mask):返回(ZF == 0 && CF == 0)
  • _mm_test_all_zeros (__m128i a, __m128i mask):返回ZF

另外還有一個更簡單地命名的版本:

  • int _mm_testc_si128 (__m128i a, __m128i b):返回CF
  • int _mm_testnzc_si128 (__m128i a, __m128i b):迴歸小號(ZF == 0 && CF == 0)
  • int _mm_testz_si128 (__m128i a, __m128i b):返回ZF

有AVX2 __m256i版本的內部函數,但導向只列出all_zeros和mix_ones_zeros備用名稱版本__m128i操作數。

如果你想測試從C或C++其他一些情況下,你應該使用testctestz用相同的操作數,並希望你的編譯器實現,它只是需要做一個PTEST,甚至有望使用單一JCC ,SETCC或CMOVCC來實現你的邏輯。 (我建議你檢查了ASM,至少對於你最關心的編譯器。)


注意_mm_testz_si128(v, set1(0xff))總是一樣_mm_testz_si128(v,v),因爲這是如何和作品。但是對於CF的結果並非如此。

您可以檢查矢量使用

bool is_all_ones = _mm_testc_si128(v, _mm_set1_epi8(0xff)); 

這可能是否定的速度更快,但更小的代碼尺寸,不是對所有的人,的載體的PCMPEQB則通常是全1 movemask + cmp。它不能避免需要一個向量常量。

PTEST確實具有不會破壞任一輸入操作數的優點,即使沒有AVX也是如此。

相關問題