Noa*_*oah 4 performance assembly x86-64 cpu-architecture microcoding
在一般情况下,可以使用内存或寄存器操作数的指令如何使用内存操作数变慢然后 mov + mov -> 指令 -> mov + mov
根据Agner Fog 指令表中的吞吐量和延迟(在我的案例中查看 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
Run Code Online (Sandbox Code Playgroud)
我不明白这些数字怎么可能是正确的。即使在没有可用寄存器的最坏情况下,并且您将一个寄存器存储在临时内存位置,这样做也会更快:
## 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
Run Code Online (Sandbox Code Playgroud)
作为最坏的情况,这具有比bts m,r(4 < 5)更好的吞吐量。(编者注:当它们有不同的瓶颈时,将吞吐量相加不起作用。您需要考虑 uops 和端口;这个序列应该是 2c 吞吐量,瓶颈在 1/clock 存储吞吐量上。)
并且微码指令有自己的一组寄存器,因此实际上不太可能需要这样做。任何人都可以解释为什么bts(或通常任何指令)可以比使用最坏情况的移动策略具有更高的内存、寄存器操作数吞吐量。
(编者注:是的,微码可以使用一些隐藏的临时寄存器。类似的东西add [mem], reg至少在逻辑上只是加载到其中之一然后存储结果。)
您缺少的是 BT、BTC、BTS 和 BTR 不像您在使用内存操作数时所描述的那样工作。您假设内存版本与寄存器版本的工作方式相同,但事实并非如此。对于寄存器版本,使用的第二个操作数的值取模 64(或 16 或 32)。对于内存版本,第二个操作数的值按原样使用。这意味着指令访问的实际内存位置可能不是内存操作数给出的地址,而是超过它的某个位置。
例如,忽略保存寄存器和原子性的需要,要获得与BTS [rsi + rdi], rax使用 BTS 的寄存器版本相同的操作,您需要执行以下操作:
LEA rbx, [rsi + rdi]
MOV rcx, rax
SHR rcx, 8
MOV rdx, [rbx + rcx]
BTS rdx, rax
MOV [rbx + rcx], rdx
Run Code Online (Sandbox Code Playgroud)
如果您知道 RAX 的值小于 64,或者它是一个更简单的内存操作数,则可以简化此操作。事实上,正如您所注意到的,在这种情况下,使用较慢的寄存器版本比使用较慢的内存版本可能是一种优势,即使这意味着更多的指令。
| 归档时间: |
|
| 查看次数: |
122 次 |
| 最近记录: |