c++ - 如何使用 SSE 高效地进行 int8/int64 转换?

标签 c++ x86 sse simd intrinsics

我正在 SSE 类型之间实现转换,我发现为 SSE4.1 之前的目标实现 int8->int64 扩展转换很麻烦。

最直接的实现是:

inline __m128i convert_i8_i64(__m128i a)
{
#ifdef __SSE4_1__
    return _mm_cvtepi8_epi64(a);
#else
    a = _mm_unpacklo_epi8(a, a);
    a = _mm_unpacklo_epi16(a, a);
    a = _mm_unpacklo_epi32(a, a);
    return _mm_srai_epi64(a, 56); // missing instrinsic!
#endif
}

但是由于 _mm_srai_epi64 在 AVX-512 之前不存在,此时有两个选项:

  • 实现_mm_srai_epi64,或
  • 以不同的方式实现convert_i8_i64

我不确定哪一个是最有效的解决方案。有什么想法吗?

最佳答案

解包内在函数在这里以一种有趣的方式使用。他们“复制”数据,而不是像人们期望的那样添加符号扩展。例如,在第一次迭代之前,您的寄存器中有以下内容

x x x x x x x x x x x x x x a b

如果将 ab 转换为 16 位,您应该得到:

x x x x x x x x x x x x A a B b

这里的ABab的符号扩展,即它们都是是 0 或 -1。

取而代之的是,您的代码给出了

x x x x x x x x x x x x a a b b

然后通过右移将其转换为正确的结果。

但是,您没有义务在“解包”内在函数中两次使用相同的操作数。如果您“解包”以下两个寄存器,您可以获得所需的结果:

x x x x x x x x x x x x x x a b
x x x x x x x x x x x x x x A B

即:

a = _mm_unpacklo_epi8(a, _mm_srai_epi8(a, 8));

(如果那个 _mm_srai_epi8 内在实际存在)


您可以将相同的想法应用到转换的最后阶段。您要“解压”以下两个寄存器:

x x x x x x x x A A A a B B B b
x x x x x x x x A A A A B B B B

要获取它们,右移 32 位数据:

_mm_srai_epi32(a, 24)
_mm_srai_epi32(a, 32)

所以最后的“解压”是

_mm_unpacklo_epi32(_mm_srai_epi32(a, 24), _mm_srai_epi32(a, 32));

关于c++ - 如何使用 SSE 高效地进行 int8/int64 转换?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41335266/

相关文章:

无法使用 pure64 更改 cr3 寄存器以指向新的 pml4 方向

c - 使用矩阵算法和常量进行嵌套 for 循环调试。

gcc - 对标上交所指令

c++ - gcc 内联 asm,未知的 sse 操作码

c++ - 内存泄漏能走多远?

c++ - 旧的 32 位 linux 程序如何最终调用 64 位库?

c++ - 使用 C++ POSIX 类的 Objective C 项目

assembly - x86指令前缀解码

c++ - Clang 无法使用模板元编程编译参数包扩展

c++ - 找不到用于 DirectX 编程的 d3dcompiler_43.dll