" _mm256_cvtepi16_epi32"的反转是什么?

时间:2018-04-08 19:19:59

标签: x86 g++ intrinsics avx avx2

我想要一个AVX2(或更早)的内在函数,它将一个8宽的32位整数向量(总共256位)转换为8宽16位整数向量(总共128位)[丢弃高16位]每个元素]。 这应该是" _mm256_cvtepi16_epi32"的倒数。 如果没有直接指令,我应该如何通过一系列指令来做到这一点?

1 个答案:

答案 0 :(得分:5)

AVX512F之前没有单指令反转。 __m128i _mm256_cvtepi32_epi16(__m256i a) (VPMOVDW),也可用于512-> 256或128-> low_half_of_128。 (输入小于512位ZMM寄存器的版本也需要AVX512VL,因此只需要Skylake-X,而不是Xeon Phi KNL。)

该AVX512指令有有符号/无符号饱和版本,但只有AVX512有一个打包指令(截断每个元素的高位字节)而不是饱和。

或者使用AVX512BW,您可以使用vpermi2w模拟一个包含交叉的双输入包,从而产生两个512位输入向量的512位结果。在Skylake-AVX512上,它解码为多个shuffle uops,但VPMOVDW也是如此,它也是一个小于dword(32位)的并行交换shuffle。 http://instlatx64.atw.hu/有一个SKX uops / ports的电子表格。

SSE2 / AVX2打包指令(如_mm256_packus_epi32vpackusdw)执行有符号或无符号饱和,以及在每个128位通道内操作。这与vpmovzxwd的交叉行为不同。

但是,您可以_mm256_and_si256在打包之前清除高字节。如果你有多个输入向量,这可能会很好,因为packs_epi32需要2个输入向量并产生256位输出。

a = H G F E | D C B A    32-bit signed elements, shown from high element to low element, low 128-bit lane on the right
b = P O N M | L K J I

_mm256_packus_epi32(a, b)   16-bit unsigned elements
    P O N M H G F E  |  L K J I D C B A
      elements from first operand go to the low half of each lane

如果您可以有效地使用2x vpand / vpackuswd ymm / vpermq ymm来获得包含正确顺序的所有元素的256位向量,那么这就是&#39> s可能最好的英特尔CPU。每256位结果只有2个shuffle uops(4个uop),你可以将它们放在一个向量中。

您可以使用SSSE3 / AVX2 vpshufb_mm256_shuffle_epi8)从单个输入中提取所需的字节,并将每个128位的另一半归零lane(通过设置该元素的shuffle-control值来设置符号位)。然后使用AVX2 vpermq将两个通道中的数据混合到低128位。

__m256i trunc_elements = _mm256_shuffle_epi8(res256, shuffle_mask_32_to_16);
__m256i ordered = _mm256_permute4x64_epi64(trunc_elements, 0x58);
__m128i result  = _mm256_castsi256_si128(ordered);   // no asm instructions

因此,每128位结果为2 uop,但两个uop都是仅在支持AVX2的主流Intel CPU上的端口5上运行的shuffle。这可以作为循环的一部分,它可以完成大量工作,可以保持port0 / port1忙,或者无论如何都需要单独使用每个128位块。

对于Ryzen / Excavator,车道越过vpermq是昂贵的(因为他们将256位指令拆分为多个128位uop,并且没有真正的车道-crossing shuffle unit:http://agner.org/optimize/)。因此,您希望vextracti128 / vpor合并。或者也许vpunpcklqdq因此您可以使用set1_epi64加载相同的shuffle掩码,而不是需要一个完整的256位向量常量来将上部通道中的元素混洗到该通道的高64位。