是否有任何AVX-512内在特性在zmm寄存器中交换低256位和高256位?
我有一个512位的双值zmm寄存器。我想做的是交换zmm[0:255]和zmm[256:51]。
__m512d a = {10, 20, 30, 40, 50, 60, 70, 80};
__m512d b = _some_AVX_512_intrinsic(a);
// GOAL: b to be {50, 60, 70, 80, 10, 20, 30, 40}
有一个函数在ymm寄存器中工作,但我找不到任何在zmm寄存器中工作的排列函数。
您正在寻找可以使用立即控制操作数从2个源中洗牌128位块的vshuff64x2
。你找到的是AVX-512版本的vperm2f128
,但是AVX-512有两个版本:一个是32位元素的屏蔽,一个是64位元素的屏蔽。(屏蔽比shuffle粒度更细,因此您可以在执行此操作时对每个double进行合并或归零。)还有相同洗牌的整数和FP版本,如vshufi32x4
。
本征是_mm512_shuffle_f64x2(a,a, _MM_SHUFFLE(1,0, 3,2))
请注意,在Intel冰湖cpu上,使用vmovupd
/vextractf64x4 mem, zmm, 1
存储两个32字节的一半可能几乎一样有效。vextract
不能微融合存储地址和存储数据,但是包括Skylake-X在内的英特尔没有涉及shuffle端口。(我想不像禅宗)。如果两个存储都在同一条缓存线上,那么Intel冰湖和以后的处理器可以支持每个时钟2个32字节的存储,而不是每个时钟1个64字节的存储。(似乎store缓冲区可以将两个store提交到同一缓存行,如果它们都在队列的头部。)
如果数据来自内存,加载__m256
+vinsertf64x4
是便宜的,特别是在Zen4上,但在英特尔上它是2个上限,一个加载,一个用于任何矢量ALU端口(p0或p5)。如果掩码寄存器可以在循环迭代中保持设置,那么合并掩码256位广播可能会更便宜。比如_mm512_mask_broadcast_f64x4(_mm512_castpd256_pd512(low), 0b11110000, _mm256_loadu_pd(addr+4))
。这仍然需要一个ALU在Skylake-X和Ice Lake上,但它可以与负载微融合。
其他可以进行相同洗牌的指令包括valignq
,其旋转计数为4个qwords(对两个输入使用相同的向量)。
或者像vpermpd
这样的变量控制洗牌,但与__m256d
(4双精度)不同的是,8个元素对于具有8位控制的任意洗牌来说太宽了。
在现有的AVX-512 cpu上,像valignq
或vshuff64x2
这样的2输入洗牌具有控制向量的vpermpd
同样有效,包括在Zen4上;它有宽洗牌单位,所以它不会像Zen1那样过线太慢。也许在Xeon Phi (KNL)上,如果您必须重复执行此操作,并且不能仅加载两半或存储在两半中,则可能值得加载vpermpd
的控制向量。(https://agner.org/optimize/and https://uops.info/)