“ pcmpeqb”的等待时间-内存与xmm寄存器的关系

问题描述 投票:0回答:1

我有这两个选项:

选项1:

loop:
...
     movdqu   xmm0, [rax]
     pcmpeqb  xmm0, [.zero_table]
...
...

align 16
.zero_table:
    DQ 0, 0

选项2:

pxor xmm1, xmm1
loop:
  ...
    movdqu   xmm0, [rax]
    pcmpeqb  xmm0, xmm1
  ...
  ...

因为我们有一个循环,我认为内存操作数的延迟成本更高,所以我问这个问题...哪个选项更好并且延迟成本更低?

assembly optimization sse micro-optimization sse2
1个回答
0
投票

第二个选项显然要好得多:循环中未融合域的内容较少。因此,乱序的exec可以提前运行,并且不需要那么多的物理寄存器或加载缓冲区(或在ALU uop读取它们之前,确切地保存这些加载结果的任何内容)。 您几乎总是想从循环中提升常量。

pcmpeqb xmm, [mem]是ROB的1个融合域uop(具有该寻址模式),但是需要两个RS条目(就像一个单独的负载,然后是pcmpeqb reg,reg)。当然,恒定负载没有输入依赖性,因此可以立即执行,但是显然会浪费缓存读取和负载吞吐量资源。

唯一的问题是这个不是是否在循环内。


[微融合ALU +负载从其寄存器输入到其寄存器输出仍然仅具有常规的ALU uop延迟。乱序的exec可以尽早执行加载,因为地址没有依赖性。 https://uops.info/上有详细的数据。

但是如果rax(指针)可能没有立即准备好,那么负载使用等待时间就成为关键路径的一部分。 (地址生成需要时间。)


BTW,第一个选择很糟糕;零个XMM寄存器带有xorps或pxor xmm0,xmm0,而不是通过加载常量。

    xorps    xmm0, xmm0    ; as cheap as a NOP on Sandybridge-family, or one ALU uop on Zen
    pcmpeqb  xmm0, [rax]

但是如果您确实有其他常量需要动态创建1或2条以上的指令,那么我想不出任何真正的原因,为什么先加载该常量或取消引用该寄存器会更好。 rip-相对寻址和[register]寻址模式都可以在Sandybridge系列的后端保持微融合。当然,如果没有AVX,则必须对齐pcmpeqb的内存操作数,因此,如果您想通过将一个负载折叠到ALU op的内存源操作数中来节省前端带宽,这可能会迫使您动手。

    movdqu  xmm0, [rax]
    pcmpeqb xmm0, [rel some_constant]
© www.soinside.com 2019 - 2024. All rights reserved.