【问题标题】:How to efficiently perform int8/int64 conversion with SSE?如何使用 SSE 高效地执行 int8/int64 转换?
【发布时间】:2017-05-11 03:44:24
【问题描述】:

我正在实现 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

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

【问题讨论】:

    标签: c++ x86 sse simd intrinsics


    【解决方案1】:

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

    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));
    

    【讨论】:

      【解决方案2】:

      使用 SSSE3,您可以使用 pshufb 来避免大多数解包。使用 anatoly 的 a / A 表示法:

      ;; input in xmm0                ;; x x x x  x x x x | x x x x  x x a b
      pshufb   xmm0, [low_to_upper]   ;; a 0 0 0  0 0 0 0 | b 0 0 0  0 0 0 0
      psrad    xmm0, 24               ;; A A A a  0 0 0 0 | B B B b  0 0 0 0
      pshufb   xmm0, [bcast_signextend]; A A A A  A A A a | B B B B  B B B b
      

      如果没有 SSSE3,我认为您可以使用 PSHUFLW、PSHUFD 和 POR 来代替某些 PUNPCK 步骤。但我认为没有什么比解包更好的了,除非您使用的是 Core2 或其他慢速随机播放 CPU,其中 pshuflwpunpcklbw 快。

      【讨论】:

        猜你喜欢
        • 2016-03-08
        • 1970-01-01
        • 1970-01-01
        • 2022-07-07
        • 1970-01-01
        • 2022-01-24
        • 2013-05-14
        • 1970-01-01
        • 2012-02-21
        相关资源
        最近更新 更多