【发布时间】:2020-12-03 22:49:33
【问题描述】:
在一般情况下,可以占用内存或寄存器操作数的指令怎么会比内存操作数更慢,然后是 mov + mov -> 指令 -> mov + mov
基于在Agner Fog's instruction tables 中发现的吞吐量和延迟(在我的案例中查看 Skylake,p238)
我看到btr/bts 指令的以下数字:
instruction, operands, uops fused domain, uops unfused domain, latency, throughput
mov r,r 1 1 0-1 .25
mov m,r 1 2 2 1
mov r,m 1 1 2 .5
...
bts/btr r,r 1 1 N/A .5
bts/btr m,r 10 10 N/A 5
我看不出这些数字怎么可能是正确的。即使在最坏的情况下,没有可用的寄存器并且您将一个存储在临时内存位置,它也会更快:
## hypothetical worst-case microcode that saves/restores a scratch register
mov m,r // + 1 throughput , save a register
mov r,m // + .5 throughput , load BTS destination operand
bts r,r // + 1 throughput , do bts (or btr)
mov m,r // + 1 throughput , store result
mov r,m // + .5 throughput , restore register
在最坏的情况下,这比 bts m,r (4
而且微码指令有自己的一组寄存器,因此看起来不太可能实际需要。谁能解释为什么bts(或一般任何指令)在内存、寄存器操作数方面比使用最坏情况移动策略具有更高的吞吐量。
(编者注:是的,微码可以使用一些隐藏的临时寄存器。像add [mem], reg 这样的东西至少在逻辑上只是加载到其中一个然后存储结果。)
【问题讨论】:
-
注意位串指令的疯狂 CISC 语义;他们可以在寻址模式寻址的双字之外建立索引!!这就是它的特别之处。
-
您的模拟似乎基于 AT&T 语法,目的地位于最后。 Agner 的表是 Intel 语法,目标优先。 Skylake 有 2 个/时钟负载,1 个/时钟存储,反之亦然(希望您意识到这更有意义。)我建议在您的示例中使用 Intel 语法来保存 regs,即交换前 2 个的顺序行,以及评论的 perf 部分等。
-
我为您解决了这个问题,并留下了一些关于您的假设的注释。
标签: performance assembly x86-64 cpu-architecture microcoding