c++ - 将 __m256 的奇数元素提取到 __m128 中的有效(在 Ryzen 上)方法?

标签 c++ vectorization x86-64 sse avx2

是否有一种固有的或其他有效的方法将 AVX 寄存器的 64 位组件的高/低 32 位组件重新打包到 SSE 寄存器中?使用 AVX2 的解决方案是可以的。

到目前为止,我正在使用以下代码,但分析器显示它在 Ryzen 1800X 上运行缓慢:

// Global constant
const __m256i gHigh32Permute = _mm256_set_epi32(0, 0, 0, 0, 7, 5, 3, 1);

// ...

// function code
__m256i x = /* computed here */;
const __m128i high32 = _mm256_castsi256_si128(_mm256_permutevar8x32_epi32(x),
  gHigh32Permute); // This seems to take 3 cycles

最佳答案

在 Intel 上,您的代码将是最佳的。一条 1-uop 指令是您将获得的最好的指令。 (除了你可能想使用 vpermps 来避免任何 int/FP 旁路延迟的风险,如果你的输入 vector 是由 pd 指令而不是加载或其他东西创建的。使用 FP 洗牌的结果作为整数指令的输入在 Intel 上通常没问题,但我不太确定是否将 FP 指令的结果提供给整数洗牌。)

尽管如果针对 Intel 进行调整,您可能会尝试更改周围的代码,以便您可以洗牌到每个 128b channel 的底部 64 位,以避免使用 channel 交叉洗牌。 (然后你可以只使用 vshufps ymm,或者如果针对 KNL 进行调整,vpermilps 因为 2-input vshufps 速度较慢。)

对于 AVX512,有 _mm256_cvtepi64_epi32 (vpmovqd)它跨 channel 打包元素,并进行截断。


在 Ryzen 上,车道交叉洗牌很慢Agner Fog没有 vpermd 的数字,但他列出了 vpermps(可能在内部使用相同的硬件)3 微指令,5c 延迟,每 4c 吞吐量一个。

vextractf128 xmm, ymm, 1 在 Ryzen 上非常高效(1c 延迟,0.33c 吞吐量),这并不奇怪,因为它已经将 256b 寄存器作为两个 128b 的一半进行跟踪。 shufps 也很高效(1c 延迟,0.5c 吞吐量),并且可以让您将两个 128b 寄存器洗牌成您想要的结果。

这也为您不再需要的 2 个 vpermps 洗牌掩码节省了 2 个寄存器。

所以我建议:

__m256d x = /* computed here */;

// Tuned for Ryzen.  Sub-optimal on Intel
__m128 hi = _mm_castpd_ps(_mm256_extractf128_pd(x, 1));
__m128 lo = _mm_castpd_ps(_mm256_castpd256_pd128(x));
__m128 odd  = _mm_shuffle_ps(lo, hi, _MM_SHUFFLE(3,1,3,1));
__m128 even = _mm_shuffle_ps(lo, hi, _MM_SHUFFLE(2,0,2,0));

在 Intel 上,使用 3 次洗牌而不是 2 次洗牌可为您提供最佳吞吐量的 2/3,第一个结果的延迟为 1c。

关于c++ - 将 __m256 的奇数元素提取到 __m128 中的有效(在 Ryzen 上)方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45867072/

相关文章:

linux - 了解 libc.a 中的简单 Linux 系统调用

objective-c - Skype Mac API - 使用 AppleScript 还是 5 年前的 API?

C++ 使用 makefile 链接到库(newbe)

c++ - 修改 const 函数中的非 const 属性

c++ - 是否有作为一组 Clang 工具实现的 C++ 重构模式?

python - 矢量化:掩码的每一行都包含要掩码的数组相应行的列索引

c++ - MIPS 和 x86_64 之间对象对齐的差异

c++ - 模块 [] 未安装——为 QML 注册自定义 C++ 包装器

python - JAX vmap 行为

python - 使用 numpy vectorize 在二维数组中仅对一个轴进行矢量化