以8086汇编语言(16位)交换2个寄存器

时间:2014-10-20 15:21:50

标签: assembly cpu-registers x86-16 16-bit

有人知道如何在不使用其他变量,寄存器,堆栈或任何其他存储位置的情况下交换2个寄存器的值吗?谢谢!

像交换AX,BX。

2 个答案:

答案 0 :(得分:2)

如果您真的需要交换两个注册表, xchg ax, bx是大多数情况下所有现代CPU上最有效的方法。 (您可以构建一个案例,其中多个单uop指令可能更有效,因为由于周围代码导致一些其他奇怪的前端效应。或者对于32位操作数大小,其中零延迟mov使得3 -mov序列在Intel CPU上具有更好的临时寄存器。)

对于代码大小,xchg-with-ax仅占用一个字节。这是0x90 NOP编码来自的地方:它是xchg ax,ax或32位模式下的xchg eax,eax。在64位模式下,xchg eax,eax会将RAX截断为32位,因此0x90显式为NOP指令,也为xchg。交换任何其他寄存器对xchg r, r/m编码需要2个字节。 (如果在64位模式下需要,则为+ REX前缀。)

在实际的8086上,代码获取通常是性能瓶颈,因此xchg的最佳方式,尤其是使用单字节xchg - -AX简短形式。

对于32位/ 64位寄存器,带有临时值的3 mov条指令可以从当前英特尔CPU上xchg的移位消除中受益。 xchg在英特尔上是3 uops,所有这些都有1c延迟并且需要一个执行单元,所以一个方向有2c延迟但另一个有1c延迟。有关当前CPU如何实现它的更多微体系结构详细信息,请参阅Why is XCHG reg, reg a 3 micro-op instruction on modern Intel architectures?

在AMD Ryzen上,32/64位regs上的xchg为2 uop并在重命名阶段处理,因此它类似于并行运行的两条mov指令。在早期的AMD CPU上,它仍然是一个2 uop指令,但单向延迟为1c。

xor-swaps或add / sub swaps或mov以外的任何其他多指令序列与寄存器的xchg 相比毫无意义。它们都有2个和3个周期延迟,以及更大的代码大小。唯一值得考虑的是mov指令。

或者更好的是,展开循环或重新排列代码以便不需要交换,或只需要mov

请注意,带有内存的xchg具有隐含的lock前缀。 使用xchg内存,除非性能根本不重要,但代码大小确实如此。 (例如在引导程序中)。或者,如果你需要原子和/或完整的内存屏障,因为它们都是。

如果您需要使用内存交换寄存器而无法使用暂存寄存器,则xor-swap实际上可能是最佳选择。使用临时存储器需要复制存储器值(例如,使用push [mem]复制到堆栈,或者在加载+存储内存操作数之前首先将寄存器溢出到第二个临时存储器位置。)

到目前为止,最低延迟方式仍然是临时寄存器;通常你可以选择不在关键路径上,或者只需要重新加载(不是首先保存,因为值已经在内存中或者可以从ALU的其他寄存器中重新计算指令)。

; spill/reload another register
push  edx            ; save/restore on the stack or anywhere else

movzx edx, word [mem]    ; or just mov dx, [mem]
mov   [mem], ax
mov   eax, edx

pop   edx            ; or better, just clobber a scratch reg

使用寄存器交换内存的另外两个合理(但更糟糕的)选项是:不接触任何其他寄存器(SP除外):

; using scratch space on the stack
push [mem]           ; [mem] can be any addressing mode, e.g. [bx]
mov  [mem], ax
pop  ax              ; dep chain = load, store, reload.

或不接触任何其他内容:

; using no extra space anywhere
xor  ax, [mem]
xor  [mem], ax        ; read-modify-write has store-forwarding + ALU latency
xor  ax, [mem]        ; dep chain = load+xor, (parallel load)+xor+store, reload+xor

使用两个内存目标xor和一个内存源会导致更糟糕的吞吐量(更多存储和更长的依赖链)。

push / pop版本仅适用于可以推送/弹出的操作数大小,但xor-swap适用于任何操作数大小。如果您可以在堆栈上使用临时版,则可能更喜欢保存/恢复版本,除非您需要平衡代码大小和速度。

答案 1 :(得分:-1)

您可以使用一些数学运算来完成。我可以给你一个主意。希望它有所帮助!

我已遵循此C代码:

int i=10; j=20
i=i+j;
j=i-j;
i=i-j;

mov ax,10
mov bx,20
add ax,bx  
//mov command to copy data from accumulator to ax, I forgot the statement, now ax=30
sub bx,ax //accumulator vil b 10
//mov command to copy data from accumulator to bx, I forgot the statement now 
sub ax,bx //accumulator vil b 20
//mov command to copy data from accumulator to ax, I forgot the statement now