【问题标题】:Extract and store alternate lower 32 bits from AVX register从 AVX 寄存器中提取并存储交替的低 32 位
【发布时间】:2017-03-01 20:41:44
【问题描述】:

我有一个 __m256i 寄存器,我想从每个 64 位组中提取 4 个低 32 位,将它们打包并连续存储到内存中。即,如果__m256i寄存器包含8个32位字:{a0,a1,a2,a3,a4,a5,a6,a7},我想将四个字连续存储到内存中{a0,a2,a4,a6}

我想出了以下代码:

void mystore(uint32 *dst, const __m256i& src)
{
      __m256 ps256    = _mm256_castsi256_ps(src);
      __m128 lo128    = _mm256_extractf128_ps(ps256, 0);
      __m128 hi128    = _mm256_extractf128_ps(ps256, 1);
      __m128 pack128  = _mm_shuffle_ps(lo128, hi128, 0 + (2<<2) + (0<<4) + (2<<6));
      __m128i r    = _mm_castps_si128(pack);
     _mm256_storeu_si256( reinterpret_cast<__m128i*>(dst), r )
}

如果我是正确的,强制转换操作只是为了满足编译器类型检查,但它们实际上是等效的无操作,因此 shuffle 指令和 2 个提取指令的总延迟成本为 3,加上未对齐商店的成本。

有更快的方法吗?

谢谢

【问题讨论】:

  • _mm256_extractf128_ps(ps256, 0); 也只是一个演员表。每个 YMM 寄存器的低半部分都可以作为相应的 XMM 寄存器访问,幸运的是编译器知道这一点,并且不会因为我们编写 extract(v, 0) 而不是正确的_mm_castintrinsic 更直接地表达最佳 asm 来惩罚我们。 (类似地,编译器在您编写 _mm_extract_epi32(v, 0) 时使用 MOVD 而不是实际的 PEXTRD)。
  • 有趣,我不知道。

标签: vectorization simd intrinsics avx2


【解决方案1】:

你可以试试这样的:

const __m256i K_PERM = _mm256_setr_epi32(0, 2, 4, 6, 1, 3, 5, 7);

inline void mystore(uint32_t * dst, const __m256i & src)
{
    __m256i permuted = _mm256_permutevar8x32_epi32(src, K_PERM);
    __m128i lo128 = _mm256_extractf128_si256(permuted, 0);
    _mm_storeu_si128((__m128i*)dst, lo128);
}

【讨论】:

  • 鉴于 permute 指令的延迟为 3,基于上面的 cmets,这似乎比现有解决方案更昂贵。尽管如此,我会试一试。
  • 我认为主要限制是内存带宽(对于两种变体)。
  • 不要使用全局__m256i常量;编译器低效地初始化它们(通过在运行时复制到 BSS)。否则是的,一个vpermd 就是你想要的。 (您可以使用_mm256_castsi256_si128 代替extract,但大多数编译器会优化extract(v, 0)。)由于您只关心shuffle 结果的低128,因此您只能使用__m128i shuffle 控件,所以您不需要加载尽可能多的常量数据。 (_mm256_castsi128_si256 将其与 256 位随机播放一起使用。)
猜你喜欢
  • 2021-06-02
  • 1970-01-01
  • 2012-04-11
  • 2011-11-04
  • 2010-09-15
  • 2011-01-14
  • 1970-01-01
  • 2014-11-18
相关资源
最近更新 更多