4

我正在 JIT 编译器中动态生成一些操作码,并且正在寻找操作码对齐的指南。

1)我已经阅读了通过在调用后添加 nop 来简要“推荐”对齐的评论

2)我还阅读了有关使用 nop 优化序列以实现并行性的信息。

3)我读过操作对齐有利于“缓存”性能

通常这些评论不提供任何支持参考。阅读博客或评论说“这样做是个好主意”是一回事,但实际编写实现特定操作序列并在线实现大多数材料(尤其是博客)的编译器是另一回事用于实际应用。所以我相信自己会发现事情(反汇编等,看看现实世界的应用程序做了什么)。这是我需要一些外部信息的一种情况。

我注意到编译器通常会在之前的任何指令序列之后立即启动奇数字节指令。所以编译器在大多数情况下并没有特别注意。我在这里或那里看到“nop”,但通常似乎很少使用 nop,如果有的话。操作码对齐有多重要?您能否为我可以实际用于实施的案例提供参考?谢谢。

4

2 回答 2

5

除了分支目标的对齐之外,我建议不要插入 nop。在某些特定的 CPU 上,分支预测算法可能会惩罚控制传输以控制传输,因此 nop 可能能够充当标志并反转预测,但否则它不太可能有帮助。

无论如何,现代 CPU 都会将您的 ISA 操作转换为微操作。这可能会使经典的对齐技术变得不那么重要,因为微操作转码器可能会忽略 nop 并改变秘密真正机器操作的大小和对齐方式。

然而,出于同样的原因,基于第一原则的优化应该不会或几乎没有伤害。

理论是通过在高速缓存行边界开始循环来更好地利用高速缓存。如果循环从缓存行的中间开始,那么缓存行的前半部分将不可避免地加载并在循环期间保持加载,如果循环长于 1/ 则这将浪费缓存中的空间2 个缓存行。

此外,对于分支目标,缓存行的初始加载会在目标对齐时加载指令流的最大前向窗口。

关于用 nops 分离不是分支目标的内联指令,在现代 CPU 上这样做的理由很少。(曾经有一段时间,RISC 机器有延迟槽,这通常会导致在控制传输后插入 nop。)对指令流进行解码很容易流水线化,如果架构具有奇字节长度的操作,则可以确保它们被合理解码.

于 2010-03-21T03:48:30.213 回答
4

所有这些微优化的最佳来源是Agner Fog 的 x86 优化手册。这些文件应该有你需要的一切,然后是一些。:)

我能想到的一件事是对齐循环,以便循环代码不会跨越任何缓存行边界,即循环小于 64 字节,并且从可被 64 整除的地址开始。然后整个循环将适合单个缓存行,并为其他事情留下更多的缓存行。我怀疑这在现实世界的程序中会很重要,不管那个特定的循环有多“热”。

于 2010-03-21T03:13:15.007 回答