【问题标题】:Store lower 16 bits of each AVX 32-bit element to memory将每个 AVX 32 位元素的低 16 位存储到内存中
【发布时间】:2021-06-02 13:46:19
【问题描述】:

我在一个 AVX 值 __m256i 中有 8 个整数值,它们的上限都是 0xffff,所以高 16 位都是零。

现在我想将这 8 个值存储为 8 个连续的 uint16_t 值。

我怎样才能以这种方式将它们写入内存?我可以以某种方式将 8 个打包整数的 __m256i 值转换为包含 8 个打包短裤的 __m128i 值吗?

我的目标是 AVX2 内在函数,但如果它可以在 AVX 内在函数中完成,那就更好了。

【问题讨论】:

  • 使用_mm256_packus_epi32 可以将2 个__m256i 寄存器合并为一个,但结果会被打乱。或者,提取一个寄存器的上半部分并使用_mm_packus_epi32
  • 当您说“lane”时,您是指 32 位 SIMD 元素吗?不是 AVX / AVX2 向量的两个 128 位一半之一?在 AVX 术语中,这是“车道”的常用用法,如“vpermilps 是车道内随机播放,但 vpermd 是车道交叉”。并且“在 AVX-512 之前,没有比 32 位更窄的车道交叉洗牌”。我知道在 ARM NEON 和其他一些 SIMD 上下文中,“lane”用于表示“元素”,但通常不适用于 x86。
  • 对于 AVX2,使用_mm256_packus_epi32 + _mm256_permutex_epi64 来修复打包的通道内行为,就像@chtz 说的那样。使用 AVX1,提取一个向量的高半部分并打包成一个__m128i。这将花费相同的 2 次 shuffle 微指令,但会产生一半的数据输出宽度。 (尽管在 Zen1 上 YMM 寄存器被视为 2x 128 位的一半是很好的。)

标签: intrinsics avx avx2 narrowing


【解决方案1】:

对于 AVX2,使用 _mm256_packus_epi32 + _mm256_permutex_epi64 来修复打包两个 __m256i 输入的通道内行为,就像 @chtz 说的那样。然后,您可以存储 64 字节输入中的所有 32 字节输出。

使用 AVX1,提取一个向量的高半部分并将_mm_packus_epi32 打包成一个__m128i。这仍然需要 2 个 shuffle 指令,但会产生一半的数据输出宽度。 (尽管在 Zen1 上很好,YMM 寄存器无论如何都被视为 2x 128 位一半,而且 vextractf128 在 Zen1 上比在 CPU 上更便宜,因为它是一个实际的 shuffle。)

当然,只有 AVX1,你不太可能在 __m256i 中有整数数据,除非它是从内存中加载的,在这种情况下,你应该首先做 _mm_loadu_si128。但是对于 AVX2,可能值得进行 32 字节加载,即使这意味着您需要每次存储 2 次随机播放而不是 1 次。尤其是如果您的任何输入未按 16 对齐。

【讨论】:

    猜你喜欢
    • 2017-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-14
    • 2012-04-11
    • 1970-01-01
    相关资源
    最近更新 更多