除了测试单个寄存器是否为全零以外,您还可以用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

最佳答案

不,除非我缺少聪明的东西,否则带有两个未知寄存器的ptest通常对于检查有关两者的某些属性没有用。 (除了明显的东西,您已经想要按位与,例如两个位图之间的交集)。

要测试两个寄存器是否均为全零,或将它们在一起或对它进行PTEST测试。
ptest xmm0, xmm1产生两个结果:

  • ZF = xmm0 & xmm1是否为全零?
  • CF = (~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
    

    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(针对全1的矢量,然后是通常的movemask + cmp)相比,这可能不会比PCMPEQB更快,但代码大小更小。它不能避免需要向量常量。

    PTEST确实具有即使不使用AVX也不破坏任何一个输入操作数的优点。

    关于assembly - PTEST可以用来测试两个寄存器是否均为零或其他情况吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43712243/

    10-11 18:42