x86指令编码如何选择操作码

x86 instruction encoding how to choose opcode

当为 x86-64 编码指令cmpw %ax -5时,来自 Intel-instruction-set-reference-manual,我有两个操作码可供选择:

3D iw CMP AX, imm16 I Valid Valid Compare imm16 with AX.
83 /7 ib CMP r/m16, imm8 MI Valid Valid Compare imm8 with r/m16.

所以会有两个编码结果:

66 3d fb ff ; this for opcode 3d
66 83 f8 fb ; this for opcode 83

那哪个更好呢?

我在下面尝试了一些在线反汇编程序

两者都可以反汇编到原始指令。但是为什么 6683fb00 也有效而 663dfb 不有效。

两种编码的长度相同,因此这无助于我们做出决定。

然而,正如@Michael Petch 评论的那样,imm16 编码将导致 Intel CPU 上的解码器出现 LCP 停顿。 (因为没有 66 操作数大小前缀,它将是 3D imm32,所以操作数大小前缀改变了指令的 rest 的长度。这这就是它被称为 Length-Changing-Prefix stall 的原因。据我所知,使用 32 位立即数时,您会在 16 位代码中得到相同的停顿。)

imm8 编码不会在我所知道的任何微体系结构上造成问题,所以喜欢它。 请参阅 Agner Fog's microarch.pdf, and other links from the 标签 wiki。

值得使用更长的指令来避免 LCP 停顿。 (例如,如果您知道寄存器的高 16 位为零或符号扩展,则使用 32 位操作数大小可以避免 LCP 停顿。)

Intel SnB 系列 CPU 有一个 uop 高速缓存,因此指令在执行前不必总是重新解码。尽管如此,uop 缓存很小,所以还是值得的。

当然,如果您针对 AMD 进行调整,那么这不是一个因素。我忘记了 Atom 和 Silvermont 解码器是否也有 LCP 停顿。


回复:第 2 部分:

663dcmp ax, imm16 的前缀+操作码。 663dfb 不会 "work" 因为它消耗了后续指令的第一个字节。当解码器看到 66 3D 时,它从指令流中抓取接下来的 2 个字节作为立即数。