AVX512在zmm寄存器中交换低256位和高256位



是否有任何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上,像valignqvshuff64x2这样的2输入洗牌具有控制向量的vpermpd同样有效,包括在Zen4上;它有宽洗牌单位,所以它不会像Zen1那样过线太慢。也许在Xeon Phi (KNL)上,如果您必须重复执行此操作,并且不能仅加载两半或存储在两半中,则可能值得加载vpermpd的控制向量。(https://agner.org/optimize/and https://uops.info/)

最新更新