我试图找到将替换的指令MOVZX
,因为我使用的是 EMU8086(它模拟不支持的 8086 MOVZX
)。
我找到的最接近的指令是CBW
,它将值放入寄存器AX
,但它仅用于有符号值。我需要一些适用于无符号值的东西。
我有哪些选择?是否可以用一条指令来完成?
该movzx
指令零扩展具有较小宽度的值以适应较大宽度的寄存器。例如,movzx
将用于将 16 位值移动到 32 位寄存器中。(它与 相比movsx
,除了符号扩展之外,它做同样的事情。当值是无符号时,你会使用movzx
,当值是有符号movsx
时。)
正如您所指出的,这些指令直到 386 才引入,因此如果您的目标是较早一代的处理器,那么您需要找到替代方案。
正如其他人在评论中指出的那样,基本策略是首先将目标寄存器归零,然后将较小的值移入. 这将完成与movzx
. 将寄存器归零的明显方法是使用mov reg, 0
,但使用 来实现它更小更快xor reg, reg
。因此,代码如下:
movzx edx, WORD PTR [bx]
可以替换为:
xor edx, edx
mov dx, WORD PTR [bx]
在现代处理器上,这比 慢,但在相对较慢movzx
的 386 和 486 上实际上会更快。movzx
当然,在movzx
不存在的处理器上,您别无选择。您可以通过更早地发出xor
指令并将其散布在其他代码中来进一步降低成本。
这种方法的一个显着缺点是您不能对存储在寄存器中的值进行就地零扩展。也就是说,当您有以下代码时,无法使用此技巧:
movzx edx, dx
相反,您必须使用临时寄存器:
xor eax, eax
mov ax, dx
mov dx, ax ; optional, if you really needed the result to be in DX
或者,如果您对 8 位值进行零扩展,您可以利用这样一个事实,即 16 位寄存器的高 8 位和低 8 位可以在 x86 上独立访问,只需将高 8 位归零. 例如:
mov al, BYTE PTR [bx]
xor ah, ah
; now read from value in AX
请注意,这适用于就地零扩展——只需将高 8 位归零。但是,这种技术不能用于对 16 位值进行零扩展,因为无法仅访问 32 位寄存器的高 16 位。
幸运的是,这些旧架构对零扩展的需求比现代架构要少得多,因为您不必如此积极地防范部分寄存器停顿和错误的依赖关系。
在评论中,有人担心所有替代方案都movzx
需要不止一条指令。当然,这是真的。如果有一种方法可以在一条指令中完成,那么 386 就不需要引入movzx
. 如果您担心执行速度,请考虑我上面所说的xor
+mov
将与可用时一样快movzx
,如果不是更快的话。
如果您担心指令的数量,请放心,更少的代码并不一定意味着更快的代码。事实上,在很多情况下,添加额外的指令可以让你的程序执行得更快。如果您正在尝试优化特定代码块,我鼓励您在此处或在Code Review上提出有关它的问题(我们需要更多的汇编语言问题!)。