【发布时间】:2022-01-22 23:38:45
【问题描述】:
有没有一种有效的方法可以使用 AVX2 和 SSE 将较大的整数类型转换为较小的整数类型(当然还有截断)?
如:
- int16 -> int8
- int32 -> int16 / int32 -> int8
- int64 -> int32 / int64 -> int16 / int64 -> int8
我知道 AVX-512 有说明:
- vpmovqb
- vpmovwb
对应的内在函数如下:
- _mm512_cvtepi16_epi8(AVX512 字节和字 ISA)
- _mm512_cvtepi32_epi8(AVX512 基础)
- _mm512_cvtepi32_epi16(AVX512 基础)
- _mm512_cvtepi64_epi8(AVX512 基础)
- _mm512_cvtepi64_epi16(AVX512 基础)
- _mm512_cvtepi64_epi32(AVX512 基础)
它处理整数类型缩小转换,但是在没有此类指令的 AVX2 和 SSE 中如何实现这一点?
请注意,虽然上述 AVX512 内部函数有 128 位和 256 位重载,但它们在运行时仍需要 AVX512。我正在寻找仅使用 AVX2 和/或 SSE 指令来完成相同任务的方法。
如果您不想给我我理解的完整答案,我知道很多要问的问题。请向我解释或帮助我找到可以为每次转换复制的算法。
另外请说明您的答案是否适用于有符号和无符号整数或其他。
非常感谢。
澄清;我不打算稍后解压这些数据。我想在许多应用程序中使用矢量化缩小转换,例如:
- 代码页转换(即UTF32 -> UTF8)(我知道不是转换数据类型那么简单)
- 数据库翻译(连接2个完全不同的数据库,并在表中单元格的数据类型不同的情况下在它们之间传输数据)
- 快速数学逼近
- 还有更多!
几乎可以做任何事情:
int32_t y = some_func();
int8_t x = static_cast
但矢量化。我已经测量了我们代码的性能(抱歉,NDA,这里不能显示),发现我们在类型转换上花费了很多时间。特别是缩小转换。编译器在使用 AVX2 可用的指令对带有符号扩展的小->大转换进行矢量化方面做得很好,但缩小转换似乎根本没有被矢量化。
还要澄清一些。我想要一种行为类似于 static_cast 的转换方法(如截断)
【问题讨论】:
-
这取决于您希望结果去哪里,例如它们如何在向量上打包/传播。也许“默认”的答案是将结果紧紧地打包在一起,这实际上是一个洗牌(AVX2 有这些)。但还有其他选择。例如:将结果留在每个其他元素中(散布着垃圾),这会花费 zero 指令(输入已经是那种形式)。或者穿插零,这需要一个 AND 指令。你需要什么?
-
或者,如果您这样做只是为了 SIMD 处理的数据密度但稍后解包(或者如果顺序无关紧要),请与
psllw交错 8 /pand/ @987654323 @ 可以将两个向量中的元素组合成包含它们的 16 位元素的低/高半部分。 -
现有一些关于包装的Q&A,很多只涉及你提到的一个具体案例;在所有此类问答中,您会发现针对不同元素大小的一些不同策略。一个有用的答案可能会链接其中一些以获取有关特定案例的详细信息。 (例如,单个向量与整个数组,值得将多个数据向量与打包指令树组合在一起,而不是一个
vpshufb) -
注:如果
y不适合int8_t,int8_t x = static_cast<int8_t>(y);的行为是实现定义的。 “截断”是指“环绕”,例如int8_t(-129) == 127? -
@chtz:这是一个 x86 问题,所以我很有信心截断意味着截断位模式,就像
_mm512_cvtepi16_epi8一样。由于 x86 使用 2 的补码有符号整数,是的,这意味着环绕。
标签: c++ c type-conversion simd avx