Pet*_*des 8 x86 assembly sse intrinsics sse4
除了测试单个寄存器是否为零之外,您还可以使用SSE4.1ptest做什么?
您是否可以使用SF和CF的组合来测试有关两个未知输入寄存器的任何有用信息?
什么是PTEST有益?您认为检查打包比较的结果(如PCMPEQD或CMPPS)会有好处,但至少在Intel CPU上,使用PTEST + JCC比使用PMOVMSK(B)进行比较和分支的成本更高./PS/PD)+宏融合CMP + JCC.
不,除非我遗漏了一些聪明的东西,ptest有两个未知的寄存器通常对检查两者的某些属性没有用.(除了明显的东西,你已经想要一个按位-AND,比如两个位图之间的交集).
要测试两个寄存器是否为全零,或者将它们组合在一起,并将PTEST与其自身对齐.
ptest xmm0, xmm1 产生两个结果:
xmm0 & xmm1全零?(~xmm0) & xmm1全零?如果第二个向量全为零,则标志根本不依赖于第一个向量中的位.
将"is-all-zero"检查视为NOT(bitwise horizontal-OR())AND和ANDNOT结果之一可能是有用的.但可能不是,因为这是我的大脑很容易思考的步骤.这个垂直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
Run Code Online (Sandbox Code Playgroud)
英特尔的内在指南列出了两个有趣的内在函数.注意args的命名:a并且mask它们告诉您有关a已知AND掩码所选部分的线索.
_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):返回 CFint _mm_testnzc_si128 (__m128i a, __m128i b):返回 (ZF == 0 && CF == 0)int _mm_testz_si128 (__m128i a, __m128i b):返回 ZF__m256i这些内在函数有AVX2 版本,但该指南仅列出了__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结果来说并非如此.
您可以检查向量是全1使用
bool is_all_ones = _mm_testc_si128(v, _mm_set1_epi8(0xff));
Run Code Online (Sandbox Code Playgroud)
这可能不是更快,但代码尺寸小于PCMPEQB对全向量的向量,然后是通常的movemask + cmp.它不能避免需要矢量常数.
PTEST确实具有即使没有AVX也不会破坏任何输入操作数的优点.