除了测试单个寄存器是否为全零以外,您还可以用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
产生两个结果:
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
Intel's intrinsics guide lists 2 interesting intrinsics for it。请注意args的命名:
a
和mask
是一个线索,它们可以告诉您有关已知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++测试其他条件,则应使用具有相同操作数的
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也不破坏任何一个输入操作数的优点。
关于assembly - PTEST可以用来测试两个寄存器是否均为零或其他情况吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/43712243/