PTEST可用于测试两个寄存器是否为零或其他条件?

时间:2017-04-30 23:03:25

标签: assembly x86 sse intrinsics sse4

除了测试单个寄存器是否全为零之外,您还可以使用SSE4.1 ptest做什么?

您可以使用SF和CF的组合来测试有关两个未知输入寄存器的任何有用信息吗?

PTEST有什么用?您认为检查打包比较的结果(如PCMPEQD或CMPPS)会有好处,但至少在Intel 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

1 个答案:

答案 0 :(得分: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版本,但该指南仅列出__m128i个操作数的all_zeros和mix_ones_zeros备用名称版本。

如果你想用C或C ++测试一些其他条件,你应该使用testctestz和相同的操作数,并希望你的编译器意识到它只需要做一个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对全向量的向量,然后是通常的movemask + cmp。它不能避免需要矢量常数。

PTEST确实具有以下优点:即使没有AVX,它也不会破坏任何输入操作数。