Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Assembly 从GP regs加载xmm_Assembly_X86_Sse_Simd_Micro Optimization - Fatal编程技术网

Assembly 从GP regs加载xmm

Assembly 从GP regs加载xmm,assembly,x86,sse,simd,micro-optimization,Assembly,X86,Sse,Simd,Micro Optimization,假设在rax和rdx中有要加载到xmm寄存器中的值 一种方法是: movq xmm0, rax pinsrq xmm0, rdx, 1 不过速度相当慢!有更好的方法吗?对于最近的Intel或AMD(我主要看了Agner Fog关于Ryzen/Skylake的表格),在延迟或uop计数方面,你不会做得更好movq+movq+punpcklqdq对于同一端口也是3个UOP 在Intel/AMD上,如果integer->vector的ALU端口上存在代码瓶颈,则将GP寄存器存储到临时位置

假设在
rax
rdx
中有要加载到
xmm
寄存器中的值

一种方法是:

movq     xmm0, rax
pinsrq   xmm0, rdx, 1

不过速度相当慢!有更好的方法吗?

对于最近的Intel或AMD(我主要看了Agner Fog关于Ryzen/Skylake的表格),在延迟或uop计数方面,你不会做得更好
movq+movq+punpcklqdq
对于同一端口也是3个UOP

在Intel/AMD上,如果integer->vector的ALU端口上存在代码瓶颈,则将GP寄存器存储到临时位置并使用16字节读取重新加载它们可能是值得考虑的吞吐量问题,integer->vector是最新Intel的端口5

在Intel上,
pinsrq x,r,imm
对于端口5是2个uop,而
movq xmm,r64
对于端口5也是1个uop

movhps-xmm,[mem]
可以微熔合负载,但它仍然需要一个端口5 ALU uop。因此,movq xmm0、rax、rdx是3个融合域UOP,其中2个需要最新Intel上的端口5。存储转发延迟使得此延迟比插入延迟显著更高

使用store/store/
movdqa
存储两个GP reg(读取两个更窄的存储和更大的负载导致的长存储转发暂停)也是3个uops,但这是避免任何端口5个uops的唯一合理顺序。大约15个周期的延迟是如此之大,以至于无序执行很容易难以隐藏它


对于YMM和/或更窄的元素,stores+reload更值得考虑,因为你将摊位分摊到更多的商店/它为你节省了更多的洗牌UOP。但它仍然不应该成为32位元素的首选策略

对于更窄的元素,如果有一种uop方法将2个窄整数打包到64位整数寄存器中,那就更好了,这样就可以设置更宽的XMM寄存器传输范围。但是没有:
shld
在英特尔SnB系列上是1个uop,但需要在寄存器顶部输入一个uop。与PowerPC或ARM相比,x86的位字段插入/提取指令非常弱,每次合并需要多条指令(除了存储/重新加载,每个时钟1的存储吞吐量很容易成为瓶颈)


AVX512F可以,合并掩蔽允许单uop插入。 根据来自(从IACA获取uop数据)的电子表格,在Skylake-AVX512上向x/y/zmm向量广播任意宽度的整数寄存器只需花费1端口5 uop

Agner似乎没有在KNL上测试过整数源regs,但类似的
vpmb2q v,k
(掩码寄存器源)是1UOP

已设置掩码寄存器:总共只有2个uops

; k1 = 0b0010

vmovq         xmm0, rax           ; 1 uop p5             ; AVX1
vpbroadcastq  xmm0{k1}, rdx       ; 1 uop p5  merge-masking
我认为合并掩蔽是“免费”的,即使对于ALU UOP也是如此。请注意,我们首先执行VMOVQ,这样可以避免对它进行更长的EVEX编码。但是,如果在掩码寄存器中有
0001
而不是
0010
,请将其与
vmovq xmm0{k1},rax混入无掩码广播

设置更多掩码寄存器后,我们可以为每个uop进行1次注册:

vmovq         xmm0, rax                         2c latency
vpbroadcastq  xmm0{k1}, rdx   ; k1 = 0b0010     3c latency
vpbroadcastq  ymm0{k2}, rdi   ; k2 = 0b0100     3c latency
vpbroadcastq  ymm0{k3}, rsi   ; k3 = 0b1000     3c latency
(对于一个完整的ZMM向量,可能启动第二个dep链和
vinserti64x4
来组合256位的一半。这也意味着只有3K个寄存器而不是7个。这需要额外花费1个洗牌uop,但除非有一些软件管道,否则OoO exec可能无法在对向量执行任何操作之前隐藏7个merges=21c的延迟。)

英特尔列出的SKX上
vpbroadcastq
的延迟仍然是3c,即使目的地只有xmm,根据Instratx64电子表格引用了这一点和其他来源

同一文档确实将
vpbroadcastq xmm,xmm
列为1c延迟,因此我们在合并依赖项链中每一步得到3c延迟大概是正确的。不幸的是,合并屏蔽UOP需要目标寄存器与其他输入一样早准备就绪;因此,操作的合并部分不能单独转发


k1=2=0b0010开始,我们可以使用以下内容初始化其余内容:

KSHIFT仅在端口5(SKX)上运行,但KMOV也运行;从整数寄存器中移动每个掩码只需要花费额外的指令来首先设置整数寄存器

实际上,如果向量的上部字节填充了广播,而不是零,那么就可以使用0b1110/0b1100等作为掩码。
我们最终写出了所有的元素。我们可以从
KXNOR k0,k0,k0
开始生成一个-1并左移,但这是2个端口5 UOP与
mov eax,2
/
kmovw k1,eax
为p0156+p5


没有掩码寄存器:(没有
kmov k1,imm
,从内存加载需要多个uop,因此一次性没有使用合并掩码的3-uop选项。但是在一个循环中,如果您可以备用一些掩码寄存器,这似乎要好得多。)

这里唯一的好处是3个UOP中的一个不需要端口5

vmovsd xmm1、xmm1、xmm0也将混合这两半,但只在最近的Intel上的端口5上运行,而不是在任何向量ALU端口上运行的整数立即混合


关于整数->向量策略的更多讨论 gcc喜欢存储/重新加载,这在任何情况下都不是最优的,除非在非常罕见的绑定端口5的情况下,大量延迟无关紧要。我提出并进一步讨论了对于32位或64位元素,在各种体系结构上什么可能是最佳的

我建议将上面的
vpbroadcastq
替换为在第一个bug上使用AVX512插入


(如果编译
\u mm\u set\u epi64x
,一定要使用
-mtune=haswell
或最近的东西,以避免对默认值
mtune=generic
进行糟糕的调整。如果二进制文件只在本地机器上运行,则使用
-march=native
)。这看起来太可怕了。4个GPs与1个GPs的线性关系要差得多,不是吗
; high 256 bits: maybe better to start again with vmovq instead of continuing
vpbroadcastq  zmm0{k4}, rcx   ; k4 =0b10000     3c latency
... filling up the ZMM reg
mov      eax, 0b0010 = 2
kmovw    k1, eax
KSHIFTLW k2, k1, 1
KSHIFTLW k3, k1, 2

#  KSHIFTLW k4, k1, 3
# ...
VPBROADCASTQ  xmm1, rdx           ; 1 uop  p5      ; AVX512VL (ZMM1 for just AVX512F)
vmovq         xmm0, rax           ; 1 uop p5             ; AVX1
vpblendd      xmm0, xmm0, xmm1, 0b1100    ; 1 uop p015   ; AVX2

; SKX: 3 uops:  2p5 + p015
; KNL: 3 uops: ? + ? + FP0/1