我还想知道通过改变寄存器使用/使用额外的寄存器(如果空闲)来获得收益的可能性,以便在某些奇怪的情况下允许更长距离的代码移动?
指令调度在短距离内通常不是很重要,因为乱序执行通常是有效的.对于像某些ARM内核这样的有序CPU而言,这一点非常重要,因为在使用结果的指令之前调度负载是很重要的.它可以帮助一些甚至在高端x86上,这取决于什么样的瓶颈限制了你的执行吞吐量.有关ROB大小与物理寄存器数量有关的一些有趣内容,请参阅http://blog.stuffedcow.net/2013/05/measuring-rob-capacity/,这是无序执行的限制因素. Software-pipelining可能有助于长期依赖链,无序执行很难隐藏.
尽早将指令放在关键路径依赖关系链上会有所帮助,因为OOO调度通常会尝试执行最早就绪的优先级. (见How are x86 uops scheduled, exactly?).
现代CPU是复杂的野兽,有时重新排序的东西可能会产生影响,当你不希望它重要.有时候无法准确猜出它为何会产生影响.不同的排序会影响解码器甚至uop缓存中的前端带宽,因为有许多规则关于uop缓存(在Intel CPU上)如何将解码的uop包装成最多6个uop线.例如,Branch alignment for loops involving micro-coded instructions on Intel SnB-family CPUs
有时解释非常模糊.例如,在英特尔的优化手册Example 3-25. Re-ordering Sequence to Improve Effectiveness of Zero-Latency MOV Instructions中,他们讨论了立即覆盖零延迟-movzx结果以更快地释放内部资源. (我尝试了Haswell和Skylake的例子,并发现mov-elimination确实在更多的时候工作,但实际上它在整个周期中实际上稍微慢了一些,而不是更快.这个例子是为了显示IvyBridge的好处,可能是其3个ALU端口的瓶颈,但HSW / SKL只是dep链中资源冲突的瓶颈,似乎不需要ALU端口来处理更多的movzx指令.)
可能这也适用于eliminated mov
instructions,不仅仅是movzx,但它可能不适用.
IDK如果我想知道如果我遇到真正的优化情况(对于IvyBridge),如果英特尔的手册没有用它作为一个例子.发布与执行的uops(融合域与未融合域)的性能计数器显示消除了多少个移动uop,但如果没有优化手册说明原因,几乎不可能找出它发生的原因.重新排序附近的独立指令只是为了尝试,可以作为调整的最后一步,但在那一点上它是伏都教/黑魔法/猜测.
正如玛格丽特指出的那样,除了简单的调度之外,还有理由对指令进行重新排序.请参阅Agner Fog’s optimization and microarchitecture guides以及x86标记wiki中的其他资源以了解更多信息.
例如,由于宏观融合,将cmp / jcc和test / jcc组合在一起总是一个好主意.当您使用-march = haswell或其他东西进行编译时,您的编译器将为您执行此操作,因为这样可以启用-mtune = haswell.
如果它允许你避免一些mov指令或溢出/重新加载,它也可以打开uop其他优化机会,但这不仅仅是调度指令.