Assembly x86-指令级并行性-最佳指令顺序

Assembly x86-指令级并行性-最佳指令顺序,assembly,x86,x86-64,micro-optimization,Assembly,X86,X86 64,Micro Optimization,以下两段x86_64代码中哪一段应该最快?或者根本没有区别 ; #1 bsf rax, rdi mov rdx, -1 cmove rax, rdx vs (或#1的替代方案,更经济的寄存器 ; #1a bsf rax, rdi mov rdi, -1 cmove rax, rdi ) 是的,我知道我应该对它们进行基准测试,但我没有这些工具,而且由于目前长期的致残疾病,我现在无法进行设置。另请参见tag wiki中的

以下两段x86_64代码中哪一段应该最快?或者根本没有区别

; #1
    bsf    rax, rdi
    mov    rdx, -1
    cmove  rax, rdx
vs

(或#1的替代方案,更经济的寄存器

; #1a
    bsf    rax, rdi
    mov    rdi, -1
    cmove  rax, rdi
)


是的,我知道我应该对它们进行基准测试,但我没有这些工具,而且由于目前长期的致残疾病,我现在无法进行设置。

另请参见tag wiki中的性能链接,尤其是


除非解码/前端效果发挥作用,它们基本上是相等的,因为无序执行。(否则它取决于周围的代码,对于不同的微体系结构是不同的。)

它们都具有相同的并行性(两个链:独立的
mov
(无输入)和
bsf
(一个输入),外加一个依赖的cmov)。它足够小,对于无序执行来说,找到这种并行性是微不足道的。如果您关心的是有序原子,那么bsf和mov都可能配对

任何差异将取决于周围的代码

如果必须选择,我可能会选择
#1a
,因为这样可以减少
mov
bsf
窃取执行端口的机会
mov r64、imm32符号扩展
可以在大多数CPU上的任何端口上运行,但bsf通常不能。在INSN之前将指令放在关键路径上不会减少资源冲突,至少在循环之外,在循环之外,来自上一次迭代的非关键指令会延迟关键路径。(mov在关键路径上,但没有输入DEP,因此无序执行可以在发出后的任何时间点运行,可能在产生bsf输入的指令之前。)

我可能会使用
#1a
而不是
#1
来让代码片段使用更少的寄存器进行将来的校对。如果我对启动某个寄存器的新依赖链有特定的用途,比如后面的指令有一个错误的依赖,并且寄存器的值依赖于一个长的依赖链(或者可能缓存未命中的负载),我会使用
#1
。e、 g.如果我想使用8位或16位寄存器,或

说到这里,
bsf
可能也对Intel CPU有错误的依赖性。如果输入值为0,则英特尔CPU将保持目标不变。(ISA说dest是未定义的,但这就是Core2的实际功能,例如,这需要依赖于目标寄存器和源寄存器)。我怀疑这就是为什么
lzcnt
/
tzcnt
/
popcnt
依赖于输出寄存器的原因


说到错误依赖项:有趣的事实是,您可以通过执行
或rdx,-1
或r64,imm8
)将寄存器设置为机器代码字节数较少的所有寄存器。通常这是个坏主意,不要这样做。

另请参见标记wiki中的性能链接,尤其是


除非解码/前端效果发挥作用,它们基本上是相等的,因为无序执行。(否则它取决于周围的代码,对于不同的微体系结构是不同的。)

它们都具有相同的并行性(两个链:独立的
mov
(无输入)和
bsf
(一个输入),外加一个依赖的cmov)。它足够小,对于无序执行来说,找到这种并行性是微不足道的。如果您关心的是有序原子,那么bsf和mov可能会对

任何差异将取决于周围的代码

如果必须选择,我可能会选择
#1a
,因为这样可以减少
mov
bsf
窃取执行端口的机会
mov r64、imm32符号扩展
可以在大多数CPU上的任何端口上运行,但bsf通常不能。在INSN之前将指令放在关键路径上不会减少资源冲突,至少在循环之外,在循环之外,来自上一次迭代的非关键指令会延迟关键路径。(mov在关键路径上,但没有输入DEP,因此无序执行可以在发出后的任何时间点运行,可能在产生bsf输入的指令之前。)

我可能会使用
#1a
而不是
#1
来让代码片段使用更少的寄存器进行将来的校对。如果我对启动某个寄存器的新依赖链有特定的用途,比如后面的指令有一个错误的依赖,并且寄存器的值依赖于一个长的依赖链(或者可能缓存未命中的负载),我会使用
#1
。e、 g.如果我想使用8位或16位寄存器,或

说到这里,
bsf
可能也对Intel CPU有错误的依赖性。如果输入值为0,则英特尔CPU将保持目标不变。(ISA说dest是未定义的,但这就是Core2的实际功能,例如,这需要依赖于目标寄存器和源寄存器)。我怀疑这就是为什么
lzcnt
/
tzcnt
/
popcnt
依赖于输出寄存器的原因


说到错误依赖项:有趣的事实是,您可以通过执行
或rdx,-1
或r64,imm8
)将寄存器设置为机器代码字节数较少的所有寄存器。通常这是个坏主意,不要这样做。

这样的问题通常最好通过简单地编写代码并在多次迭代中计时来回答。@DavidHoelzer:我不同意:微基准标记很难,而且很可能由于一些不相关的原因,一个版本看起来比另一个版本快。当序列的延迟和吞吐量不同时,也很容易出错。microbench可以测试吞吐量,而实际使用对延迟敏感。这不是一个很好的问题,但答案只是“读阿格纳·福格的东西”,不是吗
; #1a
    bsf    rax, rdi
    mov    rdi, -1
    cmove  rax, rdi