在Intel上,你的代码将是最佳的。一个1-uop指令是最好的你会得到。 (除非你想使用vpermps
来避免int/FP跳过延迟的风险,如果你的输入向量是由pd
指令创建的,而不是一个加载或者什么的,那么使用FP shuffle的结果作为整数指令的输入是通常对英特尔来说很好,但我不确定是否将FP指令的结果反馈给整数随机播放。)
尽管如果调整为英特尔,您可能会尝试更改周围的代码,以便您可以拖动到底部的64位每个128b通道的比特,以避免使用通道交叉混洗。 (然后,你可以只使用vshufps ymm
,或者如果调谐KNL,vpermilps
自2输入vshufps
较慢。)
随着AVX512,有_mm256_cvtepi64_epi32
(vpmovqd
)其中包跨车道元素,截断。
在Ryzen,车道交叉洗牌慢。 Agner Fog没有vpermd
的号码,但他列出了vpermps
(它可能在内部使用相同的硬件),速度为3 uops,5c延迟,每4c吞吐量一个。因为它跟踪256b寄存器已经是两个128b的一半,所以这并不奇怪,这并不奇怪。 shufps
也是有效的(1c延迟,0.5c吞吐量),并且可以让你将两个128b寄存器混合到你想要的结果中。
这也为您节省了2个不需要的2 vpermps
洗牌口罩的注册表。
所以我建议:
__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 /三分之二,与第一个结果1C额外的延迟。
所以你想提取奇数或偶数的32位元素?即像AVX512'_mm256_cvtepi64_epi32'('vpmovqd')?我认为你不会打破1周期延迟的shuffle指令,因为在Intel处理器上,通道混洗总是有3c延迟。您的'vpermd'解决方案具有单周期吞吐量。 –
如果你需要它更快,你将不得不使周围的代码使用它,或不需要通道或什么东西!或者可能用'shufps'将两个数据源打包成一个256b结果(除非它不是通道,所以它不能解决你的问题,并且没有'vpackqd'指令,并且打包指令也不是通道交叉)。 –
@PeterCordes,是的,我想从256位寄存器提取奇数或偶数32位元素到128位寄存器。感谢您参考AVX512!我没有在Ryzen 1800X上使用它,但期待一次迁移...这些32位元素是64位double的高低部分,所以我没有看到改变周围代码的方法。 –