[英]Can PTEST be used to test if two registers are both zero or some other condition?
除了測試單個寄存器是否為全零之外,您還可以使用SSE4.1 ptest
做什么?
您可以結合使用SF和CF來測試關於兩個未知輸入寄存器的任何有用信息嗎?
PTEST有什么用? 您可能會認為這對於檢查打包比較的結果(例如PCMPEQD或CMPPS)會很好,但是至少在Intel CPU上, 使用PTEST + JCC進行比對和分支的成本要高於PMOVMSK(B / PS / PD)+宏融合CMP + JCC。
不,除非我缺少聰明的東西,否則帶有兩個未知寄存器的ptest
通常對於檢查有關兩者的某些屬性沒有用。 (除了明顯的東西,您已經想要按位與,例如兩個位圖之間的交集)。
要測試兩個寄存器是否均為全零,或將它們在一起或對它進行PTEST測試。
ptest xmm0, xmm1
產生兩個結果:
xmm0 & xmm1
全零? (~xmm0) & xmm1
全零嗎? 如果第二個向量全為零,則標志完全不依賴於第一個向量中的位。
將“全零”檢查視為AND和ANDNOT結果的NOT(bitwise horizontal-OR())
可能有用。 但是可能不行,因為這是我的大腦不容易思考的太多步驟。 垂直與然后水平與的順序確實可以使我們更容易理解,為什么PTEST不能像整數TEST指令那樣告訴您太多關於兩個未知寄存器的組合。
這是2位ptest a,mask
的真值表。 希望這有助於考慮零和1與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
英特爾的內在函數指南為此列出了2種有趣的內在函數 。 請注意,args來命名: a
和mask
是一個線索,他們會告訴你有關的部分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
版本,但是本指南僅列出__m128i
操作數的all_zeros和mix_ones_zeros備用名稱版本。
如果要從C或C ++測試其他條件,則應使用具有相同操作數的testc
和testz
,並希望編譯器意識到它只需要執行一次PTEST,甚至希望使用單個JCC,SETCC或CMOVCC實現您的邏輯。 (我建議至少檢查您最關心的編譯器的asm。)
請注意, _mm_testz_si128(v, set1(0xff))
始終與_mm_testz_si128(v,v)
,因為這就是AND的工作方式。 但這對於CF結果而言並非如此。
您可以使用來檢查向量是否為全數
bool is_all_ones = _mm_testc_si128(v, _mm_set1_epi8(0xff));
與PCMPEQB(針對全1的矢量,然后是通常的movemask + cmp)相比,這可能不會比PCMPEQB更快,但代碼大小更小。 它不能避免需要向量常量。
PTEST確實具有即使不使用AVX也不會破壞任何一個輸入操作數的優點。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.