2017-08-24 78 views
5

是否有将AVX寄存器的64位组件的高/低32位组件重新打包到SSE寄存器的内在或另一种有效方法?使用AVX2的解决方案是可以的。高效(在Ryzen上)将__m256的奇数元素提取到__m128中的方法?

到目前为止我用下面的代码,但探查说,这是对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 
+1

所以你想提取奇数或偶数的32位元素?即像AVX512'_mm256_cvtepi64_epi32'('vpmovqd')?我认为你不会打破1周期延迟的shuffle指令,因为在Intel处理器上,通道混洗总是有3c延迟。您的'vpermd'解决方案具有单周期吞吐量。 –

+0

如果你需要它更快,你将不得不使周围的代码使用它,或不需要通道或什么东西!或者可能用'shufps'将两个数据源打包成一个256b结果(除非它不是通道,所以它不能解决你的问题,并且没有'vpackqd'指令,并且打包指令也不是通道交叉)。 –

+0

@PeterCordes,是的,我想从256位寄存器提取奇数或偶数32位元素到128位寄存器。感谢您参考AVX512!我没有在Ryzen 1800X上使用它,但期待一次迁移...这些32位元素是64位double的高低部分,所以我没有看到改变周围代码的方法。 –

回答

3

在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额外的延迟。

+0

我已经测量的'常量__m128i high32 = _mm256_castsi256_si128(_mm256_permutevar8x32_epi32(_mm256_castpd_si256(x)中,gHigh32Permute));'比'常量__m128i high32 = _mm_castps_si128更快(_mm256_castps256_ps128(_mm256_permutevar8x32_ps(_mm256_castpd_ps(x)中,gHigh32Permute)));' 。所以也许还有'双'到'浮动'旁路的惩罚? –

+0

@SergeRogatch:不太可能洗牌。更可能的是,'vpermd'与'vpermps'的表现不同。 (Agner没有列出他们,所以我不得不猜测)。或者,当它来自整数洗牌时,无论你消费的结果是否更好?根据Agner的说法,AMD对实际FP数学指令的浮动与双倍差异有所不同。 (当然几乎总是不相关的,但它是关于内部实现的一个线索,比如也许有一些额外的标记位与向量一起存储。) –

+0

不应将'hi'和'lo'交换为__m128 odd = _mm_shuffle_ps(hi ,lo,_MM_SHUFFLE(3,1,3,1));'? –

相关问题