_mm256_movemask_epi8 到 uint64_t

Posted

技术标签:

【中文标题】_mm256_movemask_epi8 到 uint64_t【英文标题】:_mm256_movemask_epi8 to uint64_t 【发布时间】:2020-03-12 11:54:44 【问题描述】:

谁能解释一下为什么 tr2tr4 显示不同的结果:

auto test1 = _mm256_set1_epi8(-1);

    uint64_t tr2 = _mm256_movemask_epi8(test1);
    uint32_t tr3 = _mm256_movemask_epi8(test1);
    uint64_t tr4 = tr3;

_mm256_movemask_epi8(test1) 应该返回 int32,因此将它分配给 int64 应该只分配低位。

相反,tr2 打印 0xFFFFFFFFFFFFFFFF 而 tr4 打印 0x00000000FFFFFFFF

做tr4有什么表现吗?

我对 C++ 和内在函数都是新手,所以我可能遗漏了一些明显的东西。

我正在使用 Visual Studio 2019 C++ 编译器。

【问题讨论】:

_mm256_movemask_epi8 返回一个int(当然是signed),所以这只是通常的C(或C++)类型提升规则。与 SIMD 或内在函数无关本身 【参考方案1】:

正如上面的 Paul 所说,这与使用更大整数分配有符号/无符号有关。这是一个例子:

#include <iostream>
#include <iomanip>

int main()

    int32_t negInt = -1;
    uint32_t unInt = static_cast<uint32_t>(negInt);
    int64_t negBigInt = static_cast<int64_t>(negInt);
    uint64_t unBigInt = static_cast<uint64_t>(negInt);
    uint64_t fromUnsigned = static_cast<uint64_t>(unInt);

    std::cout << std::hex;
    std::cout << "0x" << std::setfill('0') << std::setw(16) << negInt << "\n";
    std::cout << "0x" << std::setfill('0') << std::setw(16) << unInt << "\n";
    std::cout << "0x" << std::setfill('0') << std::setw(16) << negBigInt << "\n";
    std::cout << "0x" << std::setfill('0') << std::setw(16) << unBigInt << "\n";
    std::cout << "0x" << std::setfill('0') << std::setw(16) << fromUnsigned << "\n";

打印出来:

0x00000000ffffffff
0x00000000ffffffff
0xffffffffffffffff
0xffffffffffffffff
0x00000000ffffffff

所以 Paul 是对的,但值得注意的是,如果您将 signed 数字分配给更高位宽的字段,则不会发生这种情况。

【讨论】:

以上是关于_mm256_movemask_epi8 到 uint64_t的主要内容,如果未能解决你的问题,请参考以下文章

在AVX2中重现_mm256_sllv_epi16和_mm256_sllv_epi8

有没有办法用 AVX2 编写 _mm256_shldi_epi8(a,b,1) ? (向量之间每 8 位元素移位一位)

_mm256_shuffle_epi8 在这个 Game of Life 实现中有何意义?

_mm256_loadu2_m128i 内在函数在 g++ 下不可用?

矢量化:乘 _m256i 元素

将 16 位值的 __m256i 打包(饱和)到 8 位值的 __m128i?