将 16 位值的 __m256i 打包(饱和)到 8 位值的 __m128i?

Pack (with saturation) __m256i of 16-bit values to __m128i of 8-bit values?

是否有 AVX 或 AVX2 操作将 16x16 位无符号整数 (uint16_t) 值的 __m256i 转换为 16x8 位无符号整数 (uint8_t 的 __m128i ]) 值( 以低字节饱和)?

_mm256_packus_epi16() 但它使用第一个输入的前 8 个字节,然后是第二个输入的前 8 个字节,然后是第一个和第二个输入的第二个 8 字节...导致 8 个字节为一组乱序。

还有一些 AVX512 ops 似乎可以满足需要,但我不能依赖 AVX512,它在许多目标机器上都不存在...

不,你不能在 AVX/AVX2 的一条指令中做到这一点。

There is _mm256_packus_epi16() but it uses first 8 bytes from first input, then first 8 bytes from second input, and then second 8 bytes from first and second input... resulting in groups of 8 bytes being out of order.

正确安排的方法如下 (AVX2):

static inline __m128i convert(__m256i data) {
  __m128i lo_lane = _mm256_castsi256_si128(data);
  __m128i hi_lane = _mm256_extracti128_si256(data, 1);
  return _mm_packus_epi16(lo_lane, hi_lane);
}

根据 Skylake 上的 uops.info_mm256_extracti128_si256 在 p5 上是 1 µop,_mm_packus_epi16 在 p5 上是 1 µop。这意味着此代码块的吞吐量应为 2 个周期(每两个周期转换一次)。

您可以使用 _mm256_extractf128_si256 定位 AVX。跨域可能会花费额外的延迟(但吞吐量应该是相同的 AFAIK)。