为了理解Bulldozer为什么不合格,我一直在关注Agner Fog的优秀微体系结构书籍,在第178页的推土机下它有这一段。
最多三个前缀的指令可以在一个时钟周期内解码。超过三个的指令会受到很大的惩罚
前缀。带有4-7前缀的指令需要额外14-15个时钟周期
解码。 8-11前缀的指令需要20-22个时钟周期
额外的,12-14前缀的指令需要27 - 28个时钟周期
额外。因此,不建议延长NOP指令
有三个以上的前缀。此规则的前缀计数包括
操作数大小,地址大小,段,重复,锁定,REX和XOP
前缀。三字节VEX前缀计为一个,而两个字节
VEX前缀不计算在内。转义码(0F,0F38,0F3A)不计算在内。
当我搜索前缀时,我的技术定义远远超出了我的能力。或者,建议他们每个指令限制为4,这与上述摘录相冲突。
因此,简单来说,有人可以解释他们是/做什么以及为什么你可能想要将多达14+用于指令而不是分解?
通常情况下,您可以根据需要使用尽可能多的指令和操作数来确定。汇编程序会自动发出一些前缀,而其他人则可以手动使用。
他们提到的情况是多字节的 NOP
传统上用于对齐填充,其中的想法是使用单个但适当长的指令来节省资源。显然,事实证明,使用更多的前缀只是为了保持单个指令可能比使用两个前缀更少的指令更糟糕。
此规则的前缀计数包括操作数大小,地址大小,段,重复,锁定,REX和XOP前缀。三字节VEX前缀计为一,而两字节VEX前缀不计。
例子:
- 操作数大小:可以在32位和16位寄存器之间切换,例如
mov ax, [foo]
编码与...相同 mov eax, [foo]
但是带有前缀 66h
- 地址大小:可以在32/16或64/32位地址大小之间切换,例如
mov [eax], foo
编码与...相同 mov [rax], foo
但是带有前缀 67h
(在64位模式下)
- 段:可以覆盖使用的段,例如
mov [fs:eax], foo
编码与...相同 mov [eax], foo
但是带有前缀 64h
。
- repeat:用于字符串指令重复,例如
rep cmpsb
是编码相同的 cmpsb
但是带有前缀 f3h
- 锁:与某些指令一起使用以使它们成为原子,例如:
lock add [foo], 1
编码与...相同 add [foo], 1
但是带有前缀 f0h
- REX.W:用于切换到64位操作数大小,例如
add rax, 1
编码与...相同 add eax, 1
但是带有前缀 48h
- REX.R,B,X:用作modr / m字节的扩展以访问额外的寄存器,例如:
add r8d, 1
是相同的 add eax, 1
但是带有前缀 41h
- XOP,VEX:与向量指令子集一起使用
“四个前缀”交易来自“前缀组”:
- 锁定/ REP / REPNE
- 段覆盖
- 操作数大小覆盖
- 地址大小覆盖
您可以重复前缀,但您不能(您可以,但行为未定义)使用多个前缀 不同 来自同一组的前缀。虽然这仅适用于第1组和第2组,但其他组中每组只有1件事。
就像是 66 66 66 66 66 66 66 66 90
是有效的(但可能很慢解码)。 2E 3E 00 00
(混合段覆盖)不是。
当必须执行字节时,堆栈前缀对于代码对齐非常有用,与填充不同 nop
它不会花费执行时间。一次使用太多可能会花费解码时间。