测试AVX寄存器是否包含一些相等的整数

时间:2017-06-15 19:19:16

标签: c++ x86 simd avx avx2

考虑一个包含四个64位整数的256位寄存器。 在AVX / AVX2中是否可以有效地测试这些整数中的某些是否相等?

例如:

a){43, 17, 25, 8}:结果必须为false,因为4个数字中没有2个相等。

b){47, 17, 23, 17}:结果必须是真实的'因为数字17在AVX向量寄存器中出现2次。

如果可能的话,我想在C ++中这样做,但如果有必要,我可以下载到汇编。

1 个答案:

答案 0 :(得分:7)

使用 AVX512 (AVX512VL + AVX512CD),您可以使用专为此目的而设计的VPCONFLICTQ

AVX2

通过减少冗余比较来减少一些操作:

int test1(__m256i x)
{
    __m256i x0 = _mm256_permute4x64_epi64(x, 0x4B);
    // 1 0 2 3
    // 3 2 1 0
    __m256i e0 = _mm256_cmpeq_epi64(x0, x);
    __m256i x1 = _mm256_shuffle_epi32(x, 0x4E);
    // 2 3 0 1
    // 3 2 1 0
    __m256i e1 = _mm256_cmpeq_epi64(x1, x);
    __m256i t = _mm256_or_si256(e0, e1);
    return !_mm256_testz_si256(t, _mm256_set1_epi32(-1));
}

此前:

一个简单的“比较所有东西”的方法可以用于一些shuffle,像这样(未经测试):

int hasDupe(__m256i x)
{
    __m256i x1 = _mm256_shuffle_epi32(x, 0x4E);
    __m256i x2 = _mm256_permute4x64_epi64(x, 0x4E);
    __m256i x3 = _mm256_shuffle_epi32(x2, 0x4E);
    // 2 3 0 1
    // 3 2 1 0
    __m256i e0 = _mm256_cmpeq_epi64(x1, x);
    // 1 0 3 2
    // 3 2 1 0
    __m256i e1 = _mm256_cmpeq_epi64(x2, x);
    // 0 1 2 3
    // 3 2 1 0
    __m256i e2 = _mm256_cmpeq_epi64(x3, x);
    __m256i t0 = _mm256_or_si256(_mm256_or_si256(e0, e1), e2);
    return !_mm256_testz_si256(t0, _mm256_set1_epi32(-1));
}

GCC 7将其编译为合理的代码,但Clang确实很奇怪。它似乎认为vpor没有256位版本(它完全没有)。在这种情况下,将OR添加到添加内容大致相同(将几个-1加在一起不会为零)并且不会给Clang带来麻烦(也未测试):

int hasDupe(__m256i x)
{
    __m256i x1 = _mm256_shuffle_epi32(x, 0x4E);
    __m256i x2 = _mm256_permute4x64_epi64(x, 0x4E);
    __m256i x3 = _mm256_shuffle_epi32(x2, 0x4E);
    // 2 3 0 1
    // 3 2 1 0
    __m256i e0 = _mm256_cmpeq_epi64(x1, x);
    // 1 0 3 2
    // 3 2 1 0
    __m256i e1 = _mm256_cmpeq_epi64(x2, x);
    // 0 1 2 3
    // 3 2 1 0
    __m256i e2 = _mm256_cmpeq_epi64(x3, x);
    // "OR" results, workaround for Clang being weird
    __m256i t0 = _mm256_add_epi64(_mm256_add_epi64(e0, e1), e2);
    return !_mm256_testz_si256(t0, _mm256_set1_epi32(-1));
}