通常,最好的方法是对swap个一半进行计算,而不是缩小范围,以便在两个一半中计算出相同的总和.(特别是如果您不关心Zen 4或假设的future CPU,在这些CPU中,缩小到256位具有吞吐量优势.)处理__m512d
中的2^3=8双精度应该只需要3个洗牌/添加步骤,其中一个是通道内添加对.
Your second version is correctly doing that, and looks optimal on current CPUs (Intel and Zen 4.)个
像您所做的那样,首先进行低延迟的通道内混洗对无序执行是有好处的,让更多的uop执行并提前几个周期停用,以便在调度器和Rob中为新的可能独立的工作更快腾出空间.
在当前的Intel CPU上,所有32位或更宽粒度的512位交叉车道混洗都具有相同的性能:端口5具有3c延迟的1个uop.对于具有1c延迟的端口5,通道内512比特混洗是1微微操作.
在禅宗4上,vshufpd
和vpermilpd
都有相同的时间,vpermpd
/vshuff64x2
/vshuff32x4
/valignq
也是如此.(https://uops.info/)所有这些混洗的控件都有立即操作数,因此编译器不必加载向量常量.
Any tweaks would just be based on guess-work about what might be faster on possible future CPUs,比如future 支持AVX-512的英特尔E-core,或者他们在future 的CPU中用作E-core的精简AMD Zen 4,如果他们完全改变执行单元而不仅仅是缓存的话.或者future 可能有空间容纳多个512位混洗单元的大型内核.这段代码在所有6个操作中都具有序列依赖关系,但是能够在更多端口上运行可能会让无序执行更好地同时运行这段代码和一些独立的周边代码,或者运行另一个逻辑核心.
从历史上看,使用可用的最宽粒度的洗牌一直是最好的.例如,在Zen 4上,vextractf64x4 ymm, zmm, imm
比vextractf64x2 xmm, zmm, imm
快,所以更喜欢前者来提取第三个128位的块,即使你不介意带来大量的垃圾.更少的较大块意味着更少的可能安排,更短的多路复用链,因此可能具有更低的延迟或在更多的执行单元上运行.但是没有vshuff64x4
个,只有vshuff64x2
个128位的块,所以这是我们交换256位一半的唯一好 Select .
如果专门针对Zen 4进行调整,而不考虑英特尔,则vextractf64x4
+vinsertf64x4
的总延迟比vshuff64x2 zmm
低,尽管前端的成本是2次微调而不是1次.除了插入/提取256位半部分之外,Zen 4上的512位置乱占用了它们的执行单元2个周期(1/时钟的实际吞吐量是两个端口之一的一个uop的预期吞吐量的一半,就像Zen 4如何处理其他不需要在两个半部分之间移动数据的512位uop一样).
For the middle shuffle, swapping 128-bit halves,在vshuff64x2 z,z,z,imm8
和vpermpd z,z,imm8
之间 Select .两者在当前的CPU(包括Zen 4)上都运行相同.我们可能会基于更大的粒度(以128位块而不是64位块来移动数据)来 Select vshuff64x2
,但还有另一个因素需要考虑:vpermpd z,z,imm8
在每一半中执行独立的256位混洗,因此对256位执行单元的分解微不足道.(与矢量控制版本不同,该版本在整个矢量中有8个3位索引可供 Select .)
Zen 4的混洗执行单元本质上是512位宽,因此它们只会降低512位操作的吞吐量和更高的延迟.但future 可能搭载AVX-512的英特尔E核可能不会做到这一点,运行速度可能会像Zen 1的vperm2f128 y,y,y,imm8
(8uop,尽管这看起来有点过高)或vpermps y,y,y
(3uop)一样慢.Alder Lake中的英特尔E-core设法将这些作为2个uop处理,因此,假设支持AVX-512的具有256位执行单元的E-core也可以将vshuff64x2 z,z,z,imm8
作为2个uop处理.
vshuff64x2 z,z,z,imm8
需要vperm2f128 ymm, ymm, ymm, imm
4比特的输入(因为它可以接受两个不同的输入向量),但前2个输出通道是从第一个输入 Select 的(因此只有4个可能的输入比特必须通过多路复用器路由到每个输出比特),来自第二个源的第二两个输出通道也是如此.因此,它可以分解为两个单独的512位输入/256位输出混洗,类似于256位valignq ymm,ymm,ymm, imm
或类似vperm2f128 ymm, ymm, ymm, imm
,但每个输出通道能够 Select 四个中的任何一个.(valignq zmm
实际上是最后一次洗牌的另一种可能性,但不太可能便宜.)
因此,vshuff64x2 zmm
实际上是以一种方式设计的,这可能会使使用比您想象的更窄的执行单元来实现它的成本更低,比valignq
或vpermt2ps
或其他两个输入混洗要容易得多,在其他两个输入混洗中,每个输出可以从两个512位输入的任何位置挑选.
人们可能会猜测,使用相同输入的a one-input shuffle _mm512_permute_pd(mvx, 0b01'01'01'01);
(又名vpermilpd z,z, imm
)might be more efficient on some future CPU比vshufpd z,z,z, imm
高出两倍.这在《骑士登陆》(Xeon Phi)上是真的,但我想你并不关心这一点,因为它已经停产几年了,我也没有看过它的时间是vpermpd
比vshuff64x2
.
但在Ice Lake上,更常见的vshufpd y,y,y,i
具有2/时钟吞吐量,而不是1/时钟vpermilpd y,y,i
1.那么,谁能猜到future 配备AVX-512的E核或future 可能有空间容纳多个512位洗牌单元的大内核上,哪些洗牌会更快.
摘要:
第一次洗牌vshufpd
就够了.即使向量从内存中开始,您也不需要内存源vpermilpd
,因为您需要将向量的另一个副本作为vaddpd
的输入.可以在future 的E-core上以更低的成本处理其中一个.这是一个通道内洗牌,所以它分解成多个更窄的洗牌,对于E-core来说是微不足道的.
对于中间混洗(交换128位对)来说,vpermpd
-Immediate是一个很好的 Select ;future 的E-core很可能可以有效地处理它(作为两个独立的256位半部分).不过,vshuff64x2
可以分解为两个单独的512位输入/256位输出混洗,因此也不算差.
带有向量控制操作数的vpermpd
不容易分解,但它是一个不同的操作码,因此希望即使向量控制版本速度较慢,直接控制版本仍然会很便宜.不知何故,Alder Lake E-core确实成功地将vpermps ymm
作为2个uop运行.
vshuff64x2
或valignq
对于在Intel CPU上交换256位的一半同样好,并且在Zen 4上彼此相等.对于E-core来说,vshuff64x2
显然更容易有效地实现:两者具有相同的输入量(vshuff64x2
4位),但对于任何给定的输出位,vshuff64x2
的可能来源要少得多(4比16,并且如果两个来源不是相同的寄存器,则对哪个来源供给哪个输出的限制更多).此外,这可能是一种更常用的洗牌,因此建筑师更有可能使用晶体管来使其不太慢.
vextractf64x4
+vinsertf64x4
在Zen 4上的延迟会更低,这可能会影响也可能不会影响到周围的代码.但vshuff64x2 zmm
仍然是Zen 4上的Single-uop,只有4个周期的延迟,就像其他512位的穿越车道洗牌一样.假设带有AVX-512的较小内核可能会运行2个或更多.
Footnote 1:IDK为什么Ice Lake/Alder Lake不能使用寄存器源和立即控制将vpermilpd
解码为读取相同输入两次的vshufpd
微操作,因为在这种情况下,相同的立即位将产生相同的置乱.这似乎是一个遗漏的优化,尽管它可能会在解码器中的某个地方产生一个uop,其中内存源版本的1个输入与寄存器源版本的2个输入产生uop.因此,改为更改Shuffle执行单元以在这种情况下复制一个输入,作为让端口1处理vpermilpd
个uop的一种方式,从而使得以这种方式处理内存源并不特别.以不得不在混洗单元的端口1输入上处理更多不同的控制输入为代价?
在Ice Lake/Alder Lake上,当没有512位uop运行时,端口1执行单元可以处理一些但不是全部128位和256位混洗.它可能只是512位混洗执行单元的一半,512位混洗执行单元通常可以从端口5访问.(同样的方式,它们处理端口0或1上的256位FP数学指令,但当端口1关闭时,它作为单个512位FMA单元工作.)因此,当混洗单元的通道处于端口5的vpermilpd zmm, zmm, imm8
的上半部分时,它可以处理vpermilpd
.因此,当通过端口1访问时,似乎只需要最少的额外逻辑就能做到这一点.(vpermilpd zmm
和vshufpd zmm
以彼此相同的方式使用其立即数的高4位,并且与低4位对低半部起作用相同.每条128位通道都有2位控制输入.)
我想知道是否有意确保vpermilpd/ps
不能从FP数学运算中窃取周期(256位的端口0和1).这可能是有意义的,甚至可能对调整P01吞吐量与Shuffle吞吐量之间的瓶颈的循环很有用:他们可以使用vshufpd y, same,same, i
让它在端口1或5上运行,或者只在较小的机器代码大小(2字节VEX)上运行.或vpermilpd y, ymm/mem, i
将其限制为端口5,如果vshufpd
不需要3字节的VEX,则代价是机器代码大小的额外字节.(或者,如果它正在混洗内存源,则为整个单独的指令.但像许多具有立即操作数的指令一样,Intel CPU不能微融合Load+ALU uop,因此发布带宽的成本是相同的.)
这似乎不太可能.也许他们只是分析了现有的代码,发现shufpd
/vshufpd
更常见,因此也更重要;这并不奇怪,因为shufpd
是SSE2,而vpermilpd
直到AVX1才存在.因此,这一因素可能是影响与 Select YMM Shuffles相关的设计的原因,尽管vshufpd ymm
和vpermilpd
都是AVX1的新功能.
但对future 的猜测是,Alder Lake的英特尔Gracemont E-core性能相同,分别为vpermilpd ymm, ymm, i8
和vshufpd ymm, ymm, ymm, i8
.