【问题标题】:Check whether __m128i is zero?检查 __m128i 是否为零?
【发布时间】:2024-01-07 16:54:02
【问题描述】:

我发现了这个问题:

Is an __m128i variable zero?

我用来创建以下示例:

int main(){

    __m128i intrinreg;
    intrinreg.m128i_i64[0] = 0;
    intrinreg.m128i_i64[1] = 6;

    __m128i zero = _mm_setzero_si128();

    if (0 == _mm_movemask_epi8(_mm_cmpeq_epi32(intrinreg, zero)))
    {
        std::cout << "true" << std::endl;
    }
    else{
        std::cout << "false" << std::endl;
    }
}

但是无论我将两个 64 位 int 组件设置为 0 还是非零,我总是得到“假”打印出来?

【问题讨论】:

  • 如果值为零,那么显然与零的比较不会导致零。现在如果两个元素都不为零,它会打印“true”。
  • 如果上面返回是否所有 128 位都为零,那么将 '6' 替换为 '0' 应该会改变输出,是吗?
  • 如果你把它们都设为0,掩码应该是0xFFFF
  • 对另一个问题给出的接受答案实际上并没有回答另一个问题中提出的问题。仅当所有 32 位整数分量不等于 0 时,表达式才计算为真。如果您希望表达式在所有 64 位组件为零的情况下计算为真,您需要使用 Leonid Tsybert 在他的评论中给出的表达式:_mm_movemask_epi8(_mm_cmpeq_epi32(x,zero)) == 0xFFFF 您还应该使用 _mm_cmpeq_epi64 而不是 _epi32,但在这种情况下你会得到相同的结果。

标签: c++ assembly sse intrinsics avx


【解决方案1】:

由于您已标记 AVX,我假设您拥有 SSE4.1,在这种情况下,您想要的指令是 ptest,您可以从 _mm_testz_si128_mm_test_all_zeros() 获得。

bool test1, test2;
__m128i r1 = _mm_setzero_si128();
__m128i r2 = _mm_set1_epi64x(42);
test1 = _mm_testz_si128(r1,r1);
test2 = _mm_testz_si128(r2,r2);
printf("%d %d\n", test1, test2); //prints 1 0

如果您没有 SSE4.1,请使用 _mm_movemask_epi8(_mm_cmpeq_epi32(x,_mm_setzero_si128())) == 0xFFFF。这需要pcmpeqdpmovmskbtest

但是,ptest 设置了零标志 (ZF),因此它只需要一条指令。详情请见checking-if-two-sse-registers-are-not-both-zero-without-destroying-them

【讨论】: