如何使用SSE高效执行int8 / int64转换?

时间:2016-12-26 19:00:59

标签: 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

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

2 个答案:

答案 0 :(得分:4)

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

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

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

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

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

答案 1 :(得分:2)

使用SSSE3,您可以使用/pp/public/en?page=2来避免大多数解包。使用anatoly的pshufb / a符号:

A

如果没有SSSE3,我想你可以用PSHUFLW,PSHUFD和POR做一些事情,而不是PUNPCK的一些步骤。但是除非你在Core2或其他慢速混乱的CPU上;; 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 pshuflw更快,否则我所想到的实际上并不比解包更好。