假设我有两个256位寄存器,四个双值,x
和y
。_mm256_unpacklo_pd(x, y)
(VUNPCKLPD
)的输出为:[x0, y0, x2, y2]
(因为每个128位行都是单独处理的)。我想实现[x0, y0, x1, y1]
。
这有什么内在的/指令吗?或者,如果没有,最快达到预期效果的方法是什么?
最佳答案
请注意,所需的所有值都位于输入向量的低端。_mm_unpacklo_pd
/_mm_unpackhi_pd
在每个输入的128b下半部分将设置为vinsertf128
。(如果针对Sandybridge/Ivybridge进行调整,则可以对128b操作使用整数洗牌(vpunpcklqdq / hqdq
),以获得比FP洗牌更好的吞吐量。因为我认为这不会对任何支持AVX1的CPU造成伤害,所以这不是一个坏主意。)
如果你需要相同的东西为高和低车道,然后使用256b车道内解包指令和洗牌128b车道的结果。_m256_permute2f128_pd
尽可能使用gcc/clang编译成vinsertf128
,但不使用ICC或MSVC,因此编写
// much faster on Ryzen/KNL, same on Intel mainstream
__m256d lohalves_insert(__m256d lo, __m256d hi) {
return _mm256_insertf128_pd(lo, _mm256_castpd256_pd128(hi), 1);
}
查看各种编译器如何在the Godbolt compiler explorer上优化这些内容。
可能有一个2指令的方法来完成它,只有AVX1,但可能没有。
使用AVX2,您可以
vinsertf128
将每个输入的低128b输入到单个向量的两个通道中。然后使用AVX2vpermpd
将元素穿过车道拖到其最终位置。这在Ryzen上比两个128b
vunpckl/hpd
+vinsertf128
更糟,但在Intel上的吞吐量更好。在Intel Haswell及更高版本上,或在Sandybridge/Ivybridge上,如果不对128b操作使用整数洗牌,则2车道交叉洗牌(3+3c=6c)的延迟比1+1(资源冲突)+3c=5c更差。(请参阅Agner Fog的insn表,tag wiki中的链接。)关于c - 用于整个256位寄存器的AVX解包/解包模拟,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/45993874/